plandex-ai/plandex · error

error reading result file: %v

Error message

error reading result file: %v

What it means

The per-file goroutine in GetPlanFileResults calls os.ReadFile on the result file; any read failure (permissions, file vanished between listing and reading, I/O error) is reported on errCh as this wrapped error including the underlying os error.

Source

Thrown at app/server/db/result_helpers.go:411

	errCh := make(chan error, len(files))
	resultCh := make(chan *PlanFileResult, len(files))

	for _, file := range files {
		// log.Printf("Result file: %s", file.Name())

		go func(file os.DirEntry) {
			defer func() {
				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:

View on GitHub (pinned to e2d772072e)

Solutions

  1. Verify no concurrent job deletes files from the results directory during listing
  2. Check file permissions and ownership of the result JSON files
  3. Re-run the call; a race with cleanup is often transient
  4. Hardening: skip files that disappear mid-read instead of failing the whole call

Example fix

// before
if err != nil {
    errCh <- fmt.Errorf("error reading result file: %v", err)
    return
}
// after: tolerate files removed concurrently
if err != nil {
    if os.IsNotExist(err) {
        return // file was deleted during listing
    }
    errCh <- fmt.Errorf("error reading result file: %v", err)
    return
}
Defensive patterns

Strategy: retry

Validate before calling

fi, err := os.Stat(filepath.Join(dir, name))
if err != nil { log.Printf("result file missing/unreadable: %s", name) }

Try / catch

results, err := db.GetPlanFileResults(orgId, planId)
if err != nil && strings.Contains(err.Error(), "error reading result file") {
    time.Sleep(100 * time.Millisecond)
    results, err = db.GetPlanFileResults(orgId, planId) // transient deletion race
}

Prevention

When it happens

Trigger: File deleted or renamed by another process after ReadDir listed it; permission denied on the file; symlink pointing to a missing target.

Common situations: Concurrent cleanup of result files while GetPlanFileResults iterates; results synced/rotated externally; read-only or stale NFS mounts.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/674149f867be0523. Report an issue: GitHub.