diff --git a/cmd/tiller/environment/environment.go b/cmd/tiller/environment/environment.go
index 5e0e812160270e15b8b76fbe7f57fb141f917f13..72fd510be18e1b8f6f124c0f11ce1770aebc8fe0 100644
--- a/cmd/tiller/environment/environment.go
+++ b/cmd/tiller/environment/environment.go
@@ -23,7 +23,6 @@ These dependencies are expressed as interfaces so that alternate implementations
 package environment
 
 import (
-	"errors"
 	"io"
 
 	"k8s.io/helm/pkg/chartutil"
@@ -33,6 +32,7 @@ import (
 	"k8s.io/helm/pkg/storage"
 	"k8s.io/helm/pkg/storage/driver"
 	"k8s.io/kubernetes/pkg/client/unversioned"
+	"k8s.io/kubernetes/pkg/client/unversioned/testclient"
 )
 
 // TillerNamespace is the namespace tiller is running in.
@@ -150,7 +150,7 @@ type PrintingKubeClient struct {
 // The printing client does not have access to a Kubernetes client at all. So it
 // will always return an error if the client is accessed.
 func (p *PrintingKubeClient) APIClient() (unversioned.Interface, error) {
-	return nil, errors.New("no API client found")
+	return testclient.NewSimpleFake(), nil
 }
 
 // Create prints the values of what would be created with a real KubeClient.
diff --git a/cmd/tiller/hooks.go b/cmd/tiller/hooks.go
index e102699c7fdba1c1fe790d59f09fafaa19b99140..c0fd5be3cb29122b5a466f2cd2b3be59aece6051 100644
--- a/cmd/tiller/hooks.go
+++ b/cmd/tiller/hooks.go
@@ -48,6 +48,7 @@ var events = map[string]release.Hook_Event{
 }
 
 type simpleHead struct {
+	Version  string `json:"apiVersion"`
 	Kind     string `json:"kind,omitempty"`
 	Metadata *struct {
 		Name        string            `json:"name"`
@@ -55,7 +56,22 @@ type simpleHead struct {
 	} `json:"metadata,omitempty"`
 }
 
-// sortHooks takes a map of filename/YAML contents and sorts them into hook types.
+type versionSet map[string]struct{}
+
+func newVersionSet(apiVersions ...string) versionSet {
+	vs := versionSet{}
+	for _, v := range apiVersions {
+		vs[v] = struct{}{}
+	}
+	return vs
+}
+
+func (v versionSet) Has(apiVersion string) bool {
+	_, ok := v[apiVersion]
+	return ok
+}
+
+// sortManifests takes a map of filename/YAML contents and sorts them into hook types.
 //
 // The resulting hooks struct will be populated with all of the generated hooks.
 // Any file that does not declare one of the hook types will be placed in the
@@ -64,6 +80,7 @@ type simpleHead struct {
 // To determine hook type, this looks for a YAML structure like this:
 //
 //  kind: SomeKind
+//  apiVersion: v1
 // 	metadata:
 //		annotations:
 //			helm.sh/hook: pre-install
@@ -75,7 +92,7 @@ type simpleHead struct {
 //
 // Files that do not parse into the expected format are simply placed into a map and
 // returned.
-func sortHooks(files map[string]string) ([]*release.Hook, map[string]string, error) {
+func sortManifests(files map[string]string, apis versionSet) ([]*release.Hook, map[string]string, error) {
 	hs := []*release.Hook{}
 	generic := map[string]string{}
 
@@ -99,6 +116,10 @@ func sortHooks(files map[string]string) ([]*release.Hook, map[string]string, err
 			return hs, generic, e
 		}
 
+		if sh.Version != "" && !apis.Has(sh.Version) {
+			return hs, generic, fmt.Errorf("apiVersion %q in %s is not available", sh.Version, n)
+		}
+
 		if sh.Metadata == nil || sh.Metadata.Annotations == nil || len(sh.Metadata.Annotations) == 0 {
 			generic[n] = c
 			continue
diff --git a/cmd/tiller/hooks_test.go b/cmd/tiller/hooks_test.go
index 4d054ec90caa735feb687bc0c56d82ce939daeaa..14287a7e690657f5a31883bbd859284c3a6d6fbd 100644
--- a/cmd/tiller/hooks_test.go
+++ b/cmd/tiller/hooks_test.go
@@ -22,7 +22,7 @@ import (
 	"k8s.io/helm/pkg/proto/hapi/release"
 )
 
-func TestSortHooks(t *testing.T) {
+func TestSortManifests(t *testing.T) {
 
 	data := []struct {
 		name     string
@@ -52,6 +52,7 @@ metadata:
 			kind:  "ReplicaSet",
 			hooks: []release.Hook_Event{release.Hook_POST_INSTALL},
 			manifest: `kind: ReplicaSet
+apiVersion: v1beta1
 metadata:
   name: second
   annotations:
@@ -63,6 +64,7 @@ metadata:
 			kind:  "ReplicaSet",
 			hooks: []release.Hook_Event{},
 			manifest: `kind: ReplicaSet
+apiVersion: v1beta1
 metadata:
   name: third
   annotations:
@@ -74,6 +76,7 @@ metadata:
 			kind:  "Pod",
 			hooks: []release.Hook_Event{},
 			manifest: `kind: Pod
+apiVersion: v1
 metadata:
   name: fourth
   annotations:
@@ -85,6 +88,7 @@ metadata:
 			kind:  "ReplicaSet",
 			hooks: []release.Hook_Event{release.Hook_POST_DELETE, release.Hook_POST_INSTALL},
 			manifest: `kind: ReplicaSet
+apiVersion: v1beta1
 metadata:
   name: fifth
   annotations:
@@ -112,7 +116,7 @@ metadata:
 		manifests[o.path] = o.manifest
 	}
 
-	hs, generic, err := sortHooks(manifests)
+	hs, generic, err := sortManifests(manifests, newVersionSet("v1", "v1beta1"))
 	if err != nil {
 		t.Fatalf("Unexpected error: %s", err)
 	}
@@ -153,3 +157,19 @@ metadata:
 	}
 
 }
+
+func TestVersionSet(t *testing.T) {
+	vs := newVersionSet("v1", "v1beta1", "extensions/alpha5", "batch/v1")
+
+	if l := len(vs); l != 4 {
+		t.Errorf("Expected 4, got %d", l)
+	}
+
+	if !vs.Has("extensions/alpha5") {
+		t.Error("No match for alpha5")
+	}
+
+	if vs.Has("nosuch/extension") {
+		t.Error("Found nonexistent extension")
+	}
+}
diff --git a/cmd/tiller/release_server.go b/cmd/tiller/release_server.go
index c0336396f5766ff236efc3313984e95d17829c9c..865cf91f5868e2e1097ff1129e8198107c92adcb 100644
--- a/cmd/tiller/release_server.go
+++ b/cmd/tiller/release_server.go
@@ -35,6 +35,7 @@ import (
 	"k8s.io/helm/pkg/proto/hapi/services"
 	"k8s.io/helm/pkg/storage/driver"
 	"k8s.io/helm/pkg/timeconv"
+	"k8s.io/kubernetes/pkg/api/unversioned"
 )
 
 var srv *releaseServer
@@ -411,6 +412,31 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
 	return rel, nil
 }
 
+func (s *releaseServer) getVersionSet() (versionSet, error) {
+	defVersions := newVersionSet("v1")
+	cli, err := s.env.KubeClient.APIClient()
+	if err != nil {
+		log.Printf("API Client for Kubernetes is missing: %s.", err)
+		return defVersions, err
+	}
+
+	groups, err := cli.Discovery().ServerGroups()
+	if err != nil {
+		return defVersions, err
+	}
+
+	// FIXME: The Kubernetes test fixture for cli appears to always return nil
+	// for calls to Discovery().ServerGroups(). So in this case, we return
+	// the default API list. This is also a safe value to return in any other
+	// odd-ball case.
+	if groups == nil {
+		return defVersions, nil
+	}
+
+	versions := unversioned.ExtractGroupVersions(groups)
+	return newVersionSet(versions...), nil
+}
+
 func (s *releaseServer) renderResources(ch *chart.Chart, values chartutil.Values) ([]*release.Hook, *bytes.Buffer, error) {
 	renderer := s.engine(ch)
 	files, err := renderer.Render(ch, values)
@@ -421,7 +447,11 @@ func (s *releaseServer) renderResources(ch *chart.Chart, values chartutil.Values
 	// Sort hooks, manifests, and partials. Only hooks and manifests are returned,
 	// as partials are not used after renderer.Render. Empty manifests are also
 	// removed here.
-	hooks, manifests, err := sortHooks(files)
+	vs, err := s.getVersionSet()
+	if err != nil {
+		return nil, nil, fmt.Errorf("Could not get apiVersions from Kubernetes: %s", err)
+	}
+	hooks, manifests, err := sortManifests(files, vs)
 	if err != nil {
 		// By catching parse errors here, we can prevent bogus releases from going
 		// to Kubernetes.
diff --git a/cmd/tiller/release_server_test.go b/cmd/tiller/release_server_test.go
index 3b86c2232d563bfcece109ccf592775aa1278931..53bb8fdca01f0b746eea9afd02da9a3e722288f7 100644
--- a/cmd/tiller/release_server_test.go
+++ b/cmd/tiller/release_server_test.go
@@ -112,6 +112,20 @@ func namedReleaseStub(name string, status release.Status_Code) *release.Release
 	}
 }
 
+func TestGetVersionSet(t *testing.T) {
+	rs := rsFixture()
+	vs, err := rs.getVersionSet()
+	if err != nil {
+		t.Error(err)
+	}
+	if !vs.Has("v1") {
+		t.Errorf("Expected supported versions to at least include v1.")
+	}
+	if vs.Has("nosuchversion/v1") {
+		t.Error("Non-existent version is reported found.")
+	}
+}
+
 func TestUniqName(t *testing.T) {
 	rs := rsFixture()