{"record":{"id":"ae5a1429156da9cd","repo":"alibaba/open-code-review","slug":"unmarshal-tools-file-w","errorCode":null,"errorMessage":"unmarshal tools file: %w","messagePattern":"unmarshal tools file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/toolsconfig/toolsconfig.go","lineNumber":40,"sourceCode":"//go:embed tools.json\nvar defaultToolsJSON []byte\n\n// Load parses the tools config file. When path is empty, falls back to\n// the embedded default tools configuration.\nfunc Load(path string) ([]ToolConfigEntry, error) {\n\tvar data []byte\n\tvar err error\n\tif path == \"\" {\n\t\tdata = defaultToolsJSON\n\t} else {\n\t\tdata, err = os.ReadFile(path)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"read tools file %s: %w\", path, err)\n\t\t}\n\t}\n\tvar tools []ToolConfigEntry\n\tif err := json.Unmarshal(data, &tools); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshal tools file: %w\", err)\n\t}\n\treturn tools, nil\n}\n\n// ToolDefsByPhase returns the parsed tool definitions filtered by phase.\n// planOnly=true returns only tools with plan_task:true.\n// planOnly=false returns only tools with main_task:true.\nfunc (t *ToolConfigEntry) ToolDefsByPhase(planOnly bool) (json.RawMessage, bool) {\n\tswitch {\n\tcase planOnly && t.PlanTask:\n\t\treturn t.Definition, true\n\tcase !planOnly && t.MainTask:\n\t\treturn t.Definition, true\n\tdefault:\n\t\treturn nil, false\n\t}\n}\n","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/config/toolsconfig/toolsconfig.go#L22-L58","documentation":"Load successfully read the tools JSON but json.Unmarshal could not decode it into []ToolConfigEntry; the error wraps the decode failure. This indicates the file is malformed JSON or its structure does not match the expected array of tool entries.","triggerScenarios":"Calling Load() (default bytes) or Load(path) where the JSON is syntactically invalid, is not an array, or entries have fields with mismatched types (e.g. string where bool expected).","commonSituations":"Hand-edited tools file with a trailing comma or unquoted key; a tools file written for an older schema version whose fields changed types; someone saved a YAML file with a .json extension.","solutions":["Run the file through a JSON validator and fix syntax errors","Compare the file structure against []ToolConfigEntry and fix field names/types","Start from the built-in default tools JSON (pass empty path) and re-apply customizations"],"exampleFix":"// before\n[{\"name\":\"read_files\",\"enabled\":\"yes\"}] // wrong type\n// after\n[{\"name\":\"read_files\",\"enabled\":true}]","handlingStrategy":"validation","validationCode":"var probe []toolsconfig.ToolConfigEntry\nif err := json.Unmarshal(data, &probe); err != nil { return err } // pre-check before Load","typeGuard":null,"tryCatchPattern":"tools, err := toolsconfig.Load(path)\nif err != nil {\n    var typeErr *json.UnmarshalTypeError\n    if errors.As(err, &typeErr) { return fmt.Errorf(\"tools schema mismatch at %s: %w\", typeErr.Field, err) }\n    return err\n}","preventionTips":["Lint tools JSON files in CI with the Go struct as the schema","Version the tools file schema and check it on load","Never hand-edit JSON without re-validating; start from the default file"],"tags":["json","unmarshal","tools","config"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}