{"record":{"id":"91edf8698453dd79","repo":"plandex-ai/plandex","slug":"error-reading-description-files-v","errorCode":null,"errorMessage":"error reading description files: %v","messagePattern":"error reading description files: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/result_helpers.go","lineNumber":363,"sourceCode":"\t\t\terr = json.Unmarshal(bytes, &description)\n\n\t\t\tif err != nil {\n\t\t\t\tlog.Println(\"Error unmarshalling description file:\", path)\n\t\t\t\tlog.Println(\"bytes:\")\n\t\t\t\tlog.Println(string(bytes))\n\n\t\t\t\terrCh <- fmt.Errorf(\"error unmarshalling description file %s: %v\", path, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdescCh <- &description\n\t\t}(file)\n\t}\n\n\tfor i := 0; i < len(files); i++ {\n\t\tselect {\n\t\tcase err := <-errCh:\n\t\t\treturn nil, fmt.Errorf(\"error reading description files: %v\", err)\n\t\tcase description := <-descCh:\n\t\t\tif description.WroteFiles && description.AppliedAt == nil {\n\t\t\t\tdescriptions = append(descriptions, description)\n\t\t\t}\n\t\t}\n\t}\n\n\tsort.Slice(descriptions, func(i, j int) bool {\n\t\treturn descriptions[i].CreatedAt.Before(descriptions[j].CreatedAt)\n\t})\n\n\treturn descriptions, nil\n}\n\nfunc GetPlanFileResults(orgId, planId string) ([]*PlanFileResult, error) {\n\tvar results []*PlanFileResult\n\n\tresultsDir := getPlanResultsDir(orgId, planId)","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/result_helpers.go#L345-L381","documentation":"GetConvoMessageDescriptions fans out goroutines that report errors on errCh; this is the aggregate wrapper returned to callers when any single description file failed to read or unmarshal. It preserves the inner error (which contains the offending path) via %v.","triggerScenarios":"Any goroutine sends on errCh — typically [510] unmarshal failure or a file-read error — while the main loop collects len(files) results.","commonSituations":"One stale/corrupt file among hundreds of valid ones causes the whole listing call to fail for callers like ClearContext, invalidateConflictedResults, and PendingBuildsByPath.","solutions":["Fix or remove the specific corrupt description file named in the wrapped error","Quarantine malformed files (move out of results dir) so the listing proceeds","Hardening: log-and-skip bad files instead of failing the entire batch","Check disk state for partial writes (fs errors, ENOSPC)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"files, err := os.ReadDir(dir)\nif err == nil {\n    for _, f := range files {\n        if json.Valid(mustRead(f)) { continue } // flag bad files before calling\n        log.Printf(\"malformed description file: %s\", f.Name())\n    }\n}","typeGuard":null,"tryCatchPattern":"descs, err := db.GetConvoMessageDescriptions(...)\nif err != nil {\n    log.Printf(\"listing descriptions failed: %v\", err)\n    return nil, fmt.Errorf(\"listing descriptions: %w\", err)\n}","preventionTips":["Keep results dirs clean; archive instead of leaving partial files","Monitor for repeated wrapped errors to catch corruption early","Pin struct versions when migrating result file schemas"],"tags":["go","error-wrapping","concurrency","file-parsing"],"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"}