plandex-ai/plandex · error
error unmarshalling result file: %v
Error message
error unmarshalling result file: %v
What it means
In GetPlanFileResults' worker goroutine, json.Unmarshal fails on a result file read from the results dir. The file exists but its bytes are not valid PlanFileResult JSON — truncation, corruption, or a concurrent partial write.
Source
Thrown at app/server/db/result_helpers.go:419
if r := recover(); r != nil {
log.Printf("panic in GetPlanFileResults: %v\n%s", r, debug.Stack())
errCh <- fmt.Errorf("panic in GetPlanFileResults: %v\n%s", r, debug.Stack())
runtime.Goexit() // don't allow outer function to continue and double-send to channel
}
}()
bytes, err := os.ReadFile(filepath.Join(resultsDir, file.Name()))
if err != nil {
errCh <- fmt.Errorf("error reading result file: %v", err)
return
}
var result PlanFileResult
err = json.Unmarshal(bytes, &result)
if err != nil {
errCh <- fmt.Errorf("error unmarshalling result file: %v", err)
return
}
resultCh <- &result
}(file)
}
for i := 0; i < len(files); i++ {
select {
case err := <-errCh:
return nil, fmt.Errorf("error reading result files: %v", err)
case result := <-resultCh:
results = append(results, result)
}
}
sort.Slice(results, func(i, j int) bool {
return results[i].CreatedAt.Before(results[j].CreatedAt)View on GitHub (pinned to e2d772072e)
Solutions
- Inspect the corrupt file (delete or fix it) — the wrapped %v names the JSON offset/field
- Regenerate the result by re-running the plan
- Guard against partial writes: write to a temp file and atomically rename on completion
- Keep PlanFileResult fields tolerant (pointers/omitempty) across versions
Example fix
// before: non-atomic write can leave truncated JSON json.MarshalIndent(result, ...); os.WriteFile(path, bytes, 0644) // after: atomic write f, _ := os.CreateTemp(dir, "result-*.tmp") json.NewEncoder(f).Encode(result) f.Close() os.Rename(f.Name(), path)
Defensive patterns
Strategy: validation
Validate before calling
b, err := os.ReadFile(path)
if err == nil && !json.Valid(b) {
log.Printf("corrupt result file detected: %s", path)
} Try / catch
results, err := db.GetPlanFileResults(orgId, planId)
if err != nil && strings.Contains(err.Error(), "error unmarshalling result file") {
// locate and quarantine the file named in the wrapped error
return err
} Prevention
- Always write result JSON atomically (temp + rename)
- Keep PlanFileResult forward-compatible (pointers, omitempty)
- Validate stored JSON after any crash/recovery event
When it happens
Trigger: Result JSON is truncated (partial write), hand-edited incorrectly, or a schema change made the stored JSON incompatible with the current PlanFileResult struct (e.g. string where number is expected).
Common situations: Process killed mid-MarshalIndent leaving half-written files; version mismatch between writer and reader of result files; NaN/Infinity tokens from custom serialization.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- error unmarshalling description file %s: %v
- refresh failed - marshal: %w
- error marshalling models: %v
- error marshalling model pack: %v
- error checking custom models: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/bc88972c9b252919.
Report an issue: GitHub.