{"record":{"id":"7ddd4d861d5ee293","repo":"plandex-ai/plandex","slug":"error-unmarshalling-json-file-v","errorCode":null,"errorMessage":"error unmarshalling JSON file: %v","messagePattern":"error unmarshalling JSON file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/cli/lib/custom_models.go","lineNumber":113,"sourceCode":"\n\texists, err := fs.FileExists(path)\n\tif err != nil {\n\t\treturn CustomModelsCheckLocalChangesResult{}, err\n\t}\n\n\tif !exists {\n\t\treturn CustomModelsCheckLocalChangesResult{}, nil\n\t}\n\n\tlocalJsonData, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn CustomModelsCheckLocalChangesResult{}, fmt.Errorf(\"error reading JSON file: %v\", err)\n\t}\n\n\tvar localClientModelsInput shared.ClientModelsInput\n\terr = json.Unmarshal(localJsonData, &localClientModelsInput)\n\tif err != nil {\n\t\treturn CustomModelsCheckLocalChangesResult{}, fmt.Errorf(\"error unmarshalling JSON file: %v\", err)\n\t}\n\n\tlocalModelsInput := localClientModelsInput.ToModelsInput()\n\n\tlastSavedHash, err := os.ReadFile(hashPath)\n\n\tif err != nil && !os.IsNotExist(err) {\n\t\treturn CustomModelsCheckLocalChangesResult{}, fmt.Errorf(\"error reading hash file: %v\", err)\n\t}\n\n\tcurrentHash, err := localModelsInput.Hash()\n\tif err != nil {\n\t\treturn CustomModelsCheckLocalChangesResult{}, fmt.Errorf(\"error hashing models: %v\", err)\n\t}\n\n\treturn CustomModelsCheckLocalChangesResult{\n\t\tHasLocalChanges:  currentHash != string(lastSavedHash),\n\t\tLocalModelsInput: localModelsInput,","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/cli/lib/custom_models.go#L95-L131","documentation":"After reading the local custom-models JSON, CustomModelsCheckLocalChanges unmarshals it into shared.ClientModelsInput; a parse failure is wrapped as 'error unmarshalling JSON file: %v'. This means the file exists and is readable but its content is not valid JSON of the expected shape.","triggerScenarios":"json.Unmarshal(localJsonData, &localClientModelsInput) fails — truncated write, manual edit introduced invalid JSON, schema drift (fields changed type/shape across app versions), or empty/corrupted file.","commonSituations":"User hand-edited custom-models.json and broke the syntax; crash/interrupt during a previous write left a truncated file; upgrading the CLI changed the ClientModelsInput schema so old files no longer decode.","solutions":["Validate the JSON with a linter/parser and fix syntax errors","Delete or rename the file and rerun the custom-models sync to regenerate it","If it appeared after an upgrade, let the sync rewrite the file in the new schema","Compare the file against the expected ClientModelsInput structure for type mismatches"],"exampleFix":"// before: hard failure on malformed cache file\nerr = json.Unmarshal(localJsonData, &localClientModelsInput)\nif err != nil {\n    return CustomModelsCheckLocalChangesResult{}, fmt.Errorf(\"error unmarshalling JSON file: %v\", err)\n}\n// after: caller resets corrupted cache\nif json.Valid(localJsonData) == false {\n    os.Remove(path) // force resync\n}","handlingStrategy":"validation","validationCode":"data, err := os.ReadFile(path)\nif err == nil && !json.Valid(data) {\n    os.Remove(path) // corrupted cache; force regeneration\n}","typeGuard":"func validClientModelsInput(data []byte) bool {\n    var in shared.ClientModelsInput\n    return json.Unmarshal(data, &in) == nil\n}","tryCatchPattern":"res, err := CustomModelsCheckLocalChanges(...)\nif err != nil && strings.Contains(err.Error(), \"error unmarshalling JSON file\") {\n    os.Rename(path, path+\".bak\") // preserve for inspection, then resync\n    return SyncCustomModels()\n}","preventionTips":["Write the JSON atomically (temp file + rename) to prevent truncation","Validate JSON after manual edits before running the CLI","Migrate/reset the file when upgrading across schema versions"],"tags":["json","parsing","custom-models","schema"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}