{"record":{"id":"7833c3555b2283c8","repo":"gastownhall/beads","slug":"unable-to-parse-plugin-file-v2-w","errorCode":null,"errorMessage":"unable to parse plugin file v2: %w","messagePattern":"unable to parse plugin file v2: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/doctor/claude.go","lineNumber":570,"sourceCode":"\n\t// First, determine the format version\n\tvar versionCheck struct {\n\t\tVersion int `json:\"version\"`\n\t}\n\tif err := json.Unmarshal(data, &versionCheck); err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"unable to parse plugin file: %w\", err)\n\t}\n\n\t// Handle version 2 format (GH#741): plugins map contains arrays\n\tif versionCheck.Version == 2 {\n\t\tvar pluginDataV2 struct {\n\t\t\tPlugins map[string][]struct {\n\t\t\t\tVersion string `json:\"version\"`\n\t\t\t\tScope   string `json:\"scope\"`\n\t\t\t} `json:\"plugins\"`\n\t\t}\n\t\tif err := json.Unmarshal(data, &pluginDataV2); err != nil {\n\t\t\treturn \"\", false, fmt.Errorf(\"unable to parse plugin file v2: %w\", err)\n\t\t}\n\n\t\t// Look for beads plugin - take first entry from the array\n\t\tif entries, ok := pluginDataV2.Plugins[\"beads@beads-marketplace\"]; ok && len(entries) > 0 {\n\t\t\treturn entries[0].Version, true, nil\n\t\t}\n\t\treturn \"\", false, nil\n\t}\n\n\t// Handle version 1 format (original): plugins map contains structs directly\n\tvar pluginDataV1 struct {\n\t\tPlugins map[string]struct {\n\t\t\tVersion string `json:\"version\"`\n\t\t} `json:\"plugins\"`\n\t}\n\n\tif err := json.Unmarshal(data, &pluginDataV1); err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"unable to parse plugin file: %w\", err)","sourceCodeStart":552,"sourceCodeEnd":588,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/doctor/claude.go#L552-L588","documentation":"When installed_plugins.json declares version 2 format (GH#741), GetClaudePluginVersion unmarshals it into the v2 shape whose plugins field is a map of arrays. If the content is valid JSON but does not match that v2 structure, this error is returned.","triggerScenarios":"GetClaudePluginVersion (via CheckClaudePlugin) when versionCheck.Version == 2 and json.Unmarshal into the v2 struct fails — e.g. \"plugins\" is an array instead of an object, or entries are objects instead of arrays — at cmd/bd/doctor/claude.go:570.","commonSituations":"A Claude plugin tool changed the manifest layout while keeping version: 2; manually edited plugins map with wrong nesting; forward-compatible schema drift from a newer Claude version.","solutions":["Check the actual structure of installed_plugins.json against the v2 schema (plugins: {name: [{version, scope}]}) and fix it","Reinstall the beads plugin so Claude regenerates a schema-correct manifest","Update bd to the latest version in case newer manifest variants are supported","If a newer Claude wrote an incompatible format, report it to beads maintainers with the file contents (redact paths as needed)"],"exampleFix":"// before (invalid v2 shape)\n{\"version\":2,\"plugins\":[\"beads@beads-marketplace\"]}\n// after\n{\"version\":2,\"plugins\":{\"beads@beads-marketplace\":[{\"version\":\"0.9.1\",\"scope\":\"user\"}]}}","handlingStrategy":"type-guard","validationCode":"import \"encoding/json\", \"os\"\nfunc isV2Shape(home string) bool {\n\tdata, _ := os.ReadFile(filepath.Join(home, \".claude\", \"plugins\", \"installed_plugins.json\"))\n\tvar m struct {\n\t\tVersion int `json:\"version\"`\n\t\tPlugins map[string][]struct{ Version string `json:\"version\"` } `json:\"plugins\"`\n\t}\n\treturn json.Unmarshal(data, &m) == nil && m.Version == 2\n}","typeGuard":null,"tryCatchPattern":"_, installed, err := GetClaudePluginVersion()\nif err != nil && strings.Contains(err.Error(), \"unable to parse plugin file v2\") {\n\tlog.Printf(\"manifest claims v2 but has wrong shape: %v\", err)\n\treturn nil // handle reinstall path\n}","preventionTips":["Keep plugins maps as objects of arrays in v2 manifests ({name: [entries]})","Don't mix v1 and v2 shapes when editing manifests manually","Regenerate the manifest by reinstalling rather than hand-editing","Keep bd and the Claude plugin updated together (GH#741 format change)"],"tags":["json","schema","claude-plugin","doctor"],"backgroundTag":"json-schema-mismatch","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}