helm/helm · error
expected config media type %s for legacy compatibility, got
Error message
expected config media type %s for legacy compatibility, got %s
What it means
Thrown by registry Client.PullPlugin (pkg/registry/plugin.go) after downloading an OCI manifest. For backwards compatibility, when a manifest has no OCI 1.1 artifactType Helm requires the manifest's config descriptor mediaType to equal PluginArtifactType (application/vnd.helm.plugin.v1+json). If the artifact has neither an artifactType nor that legacy config media type, it is not a Helm plugin and the pull is rejected.
Source
Thrown at pkg/registry/plugin.go:99
manifestData, err := c.Generic().GetDescriptorData(genericResult.MemoryStore, genericResult.Manifest)
if err != nil {
return nil, fmt.Errorf("unable to retrieve manifest: %w", err)
}
// Parse the manifest to check artifact type
var manifest ocispec.Manifest
if err := json.Unmarshal(manifestData, &manifest); err != nil {
return nil, fmt.Errorf("unable to parse manifest: %w", err)
}
// Validate artifact type (for OCI v1.1+ manifests)
if manifest.ArtifactType != "" && manifest.ArtifactType != PluginArtifactType {
return nil, fmt.Errorf("expected artifact type %s, got %s", PluginArtifactType, manifest.ArtifactType)
}
// For backwards compatibility, also check config media type if no artifact type
if manifest.ArtifactType == "" && manifest.Config.MediaType != PluginArtifactType {
return nil, fmt.Errorf("expected config media type %s for legacy compatibility, got %s", PluginArtifactType, manifest.Config.MediaType)
}
// Find the plugin tarball and optional provenance using NAME-VERSION.tgz format
var pluginDescriptor *ocispec.Descriptor
var provenanceDescriptor *ocispec.Descriptor
var foundProvenanceName string
// Look for layers with the expected titles/annotations
for _, layer := range manifest.Layers {
d := layer
// Check for title annotation
if title, exists := d.Annotations[ocispec.AnnotationTitle]; exists {
// Check if this looks like a plugin tarball: {pluginName}-{version}.tgz
if pluginDescriptor == nil && strings.HasPrefix(title, pluginName+"-") && strings.HasSuffix(title, ".tgz") {
pluginDescriptor = &d
}
// Check if this looks like a plugin provenance: {pluginName}-{version}.tgz.prov
if provenanceDescriptor == nil && strings.HasPrefix(title, pluginName+"-") && strings.HasSuffix(title, ".tgz.prov") {View on GitHub (pinned to 2a29f1770b)
Solutions
- Inspect the artifact: `crane manifest <ref>` and check artifactType and config.mediaType fields
- Confirm the ref is a plugin artifact, not a chart; charts are pulled with `helm pull oci://...` not `helm plugin pull`
- Re-push the plugin with `helm plugin push`, which sets the correct artifact/config media type
- If pushing manually with oras, set --artifact-type application/vnd.helm.plugin.v1+json (or the config media type to the same value)
Example fix
# before (fails: chart artifact has no plugin config media type) helm plugin pull oci://ghcr.io/user/mychart:1.0.0 # after (plugin artifact pushed with: helm plugin push ./my-plugin oci://ghcr.io/user/my-plugin) helm plugin pull oci://ghcr.io/user/my-plugin:1.0.0
Defensive patterns
Strategy: try-catch
Try / catch
res, err := client.PullPlugin(ref, pluginName)
if err != nil {
msg := err.Error()
if strings.Contains(msg, "expected config media type") || strings.Contains(msg, "expected artifact type") {
// ref is not a Helm plugin artifact - route to chart pull or reject the input
return fmt.Errorf("%s is not a plugin artifact", ref)
}
return err
} Prevention
- Push plugins exclusively with `helm plugin push` so artifact/config media types are set correctly
- Never reuse chart OCI refs (helm push output) for plugin pulls
- Verify artifacts with `crane manifest <ref>` before wiring automated pulls
When it happens
Trigger: Calling Client.PullPlugin or `helm plugin pull`/`helm plugin install` from an oci:// ref whose manifest omits artifactType and whose config.mediaType is different, e.g. a Helm chart pushed with `helm push` (config media type application/vnd.cncf.helm.config.v1+json), a plain OCI image, or an artifact pushed with oras without the plugin config type.
Common situations: Pointing a plugin pull at a chart OCI ref instead of a plugin ref; plugins pushed with custom tooling that set a different config media type; automation scripts that mix chart and plugin references; artifacts pushed before the plugin artifact-type convention existed.
Related errors
- must specify at least one layer to pull (chart/prov)
- failed to pull plugin from %s: %w
- could not load config with mediatype %s
- manifest does not contain a layer with mediatype %s
- unable to retrieve manifest: %w
AI-assisted analysis of helm/helm@2a29f1770b (2026-08-15).
Data as JSON: /api/errors/e93700ef4c35574b.
Report an issue: GitHub.