{"record":{"id":"2399e081dd0eae0b","repo":"docker/cli","slug":"plugin-schemaversion-version-cannot-be-empty","errorCode":null,"errorMessage":"plugin SchemaVersion version cannot be empty","messagePattern":"plugin SchemaVersion version cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli-plugins/manager/plugin.go","lineNumber":143,"sourceCode":"\t\tp.Err = newPluginError(\"plugin metadata does not define a vendor\")\n\t\treturn p, nil\n\t}\n\treturn p, nil\n}\n\n// validateSchemaVersion validates if the plugin's schemaVersion is supported.\n//\n// The current schema-version is \"0.1.0\", but we don't want to break compatibility\n// until v2.0.0 of the schema version. Check for the major version to be < 2.0.0.\n//\n// Note that CLI versions before 28.4.1 may not support these versions as they were\n// hard-coded to only accept \"0.1.0\".\nfunc validateSchemaVersion(version string) error {\n\tif version == \"0.1.0\" {\n\t\treturn nil\n\t}\n\tif version == \"\" {\n\t\treturn errors.New(\"plugin SchemaVersion version cannot be empty\")\n\t}\n\tmajor, _, ok := strings.Cut(version, \".\")\n\tmajorVersion, err := strconv.Atoi(major)\n\tif !ok || err != nil {\n\t\treturn fmt.Errorf(\"plugin SchemaVersion %q has wrong format: must be <major>.<minor>.<patch>\", version)\n\t}\n\tif majorVersion > 1 {\n\t\treturn fmt.Errorf(\"plugin SchemaVersion %q is not supported: must be lower than 2.0.0\", version)\n\t}\n\treturn nil\n}\n\n// RunHook executes the plugin's hooks command\n// and returns its unprocessed output.\nfunc (p *Plugin) RunHook(ctx context.Context, hookData hooks.Request) ([]byte, error) {\n\thDataBytes, err := json.Marshal(hookData)\n\tif err != nil {\n\t\treturn nil, wrapAsPluginError(err, \"failed to marshall hook data\")","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli-plugins/manager/plugin.go#L125-L161","documentation":"validateSchemaVersion (cli-plugins/manager/plugin.go:138) checks a candidate plugin's metadata. The SchemaVersion field is mandatory; if it is the zero value (empty string) the function returns errors.New(\"plugin SchemaVersion version cannot be empty\") at line 143. This error is wrapped into Plugin.Err during newPlugin, marking the plugin as failed but still returning the Plugin (non-fatal to the CLI as a whole).","triggerScenarios":"A plugin binary whose metadata JSON omits the SchemaVersion field entirely, or sets it to \"\". The metadata is fetched by running the plugin with the metadata subcommand; a plugin that returns {} or {\"SchemaVersion\":\"\"} triggers it.","commonSituations":"Hand-written or in-development plugins that have not populated the SchemaVersion metadata; plugins built against a very old/unknown template that lacks the field; corrupt metadata output.","solutions":["Ensure the plugin's metadata output includes \"SchemaVersion\": \"0.1.0\" (or any <2.0.0 semver as accepted by validateSchemaVersion).","Run '<plugin-path> <plugin-name> docker-cli-plugin-metadata' manually and inspect the JSON to confirm the field is present and non-empty.","Also provide the required Vendor field (checked afterwards at line 124) to avoid the next validation error.","Update to a current plugin scaffold/template so all required metadata fields are emitted."],"exampleFix":"// before — plugin metadata\n{\"SchemaVersion\":\"\",\"Vendor\":\"\"}\n// after\n{\"SchemaVersion\":\"0.1.0\",\"Vendor\":\"example.com\",\"Name\":\"myplugin\"}","handlingStrategy":"validation","validationCode":"// Validate a candidate plugin's metadata before registering it:\nvar meta metadata.Metadata\nif err := json.Unmarshal(raw, &meta); err != nil { return err }\nif meta.SchemaVersion == \"\" { return errors.New(\"metadata missing SchemaVersion\") }\n// then also confirm Vendor is set","typeGuard":"// newPlugin sets Plugin.Err (a *pluginError) instead of returning a hard error;\n// callers check p.Err != nil and the plugin is listed but not invoked.\nfunc isValidPlugin(p manager.Plugin) bool { return p.Err == nil }","tryCatchPattern":"// Listing plugins already tolerates this: it surfaces the plugin with an error rather than aborting.\n// If you enumerate plugins, inspect .Err and skip:\nfor _, p := range plugins { if p.Err != nil { log.Println(\"skipping\", p.Name, p.Err); continue } }","preventionTips":["Always emit SchemaVersion (e.g. \"0.1.0\") and Vendor in plugin metadata.","Run the metadata subcommand locally and pipe through jq to confirm fields before distributing.","Pin to a plugin template/scaffold that already includes required metadata.","Keep SchemaVersion < 2.0.0; older CLIs (<28.4.1) only accept \"0.1.0\"."],"tags":["cli-plugins","metadata","plugin-protocol","configuration"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}