plandex-ai/plandex · error

failed to load context: %v

Error message

failed to load context: %v

What it means

AutoLoadContextFiles drains errCh once per input file and returns this wrapper on the first non-nil error received from any per-file goroutine. It is an aggregation point: the real cause (stat failure, read failure, or a per-file processing error) is the wrapped %v value.

Source

Thrown at app/cli/lib/context_auto_load.go:121

			}

			mu.Lock()
			loadContextReqsByIndex[index] = &shared.LoadContextParams{
				ContextType: contextType,
				FilePath:    path,
				Name:        path,
				Body:        body,
				AutoLoaded:  true,
				ImageDetail: imageDetail,
			}
			mu.Unlock()
			errCh <- nil
		}(i, path)
	}

	for range files {
		if e := <-errCh; e != nil {
			return "", fmt.Errorf("failed to load context: %v", e)
		}
	}

	// Convert map back to ordered slice
	loadContextReqs := make(shared.LoadContextRequest, 0, len(loadContextReqsByIndex))
	for i := 0; i < len(files); i++ {
		if req := loadContextReqsByIndex[i]; req != nil {
			loadContextReqs = append(loadContextReqs, req)
		}
	}

	// even if there are no files to load, we still need to hit the API endpoint because the stream is waiting on a channel for the autoload to finish
	res, apiErr := api.Client.AutoLoadContext(ctx, CurrentPlanId, CurrentBranch, loadContextReqs)
	if apiErr != nil {
		return "", fmt.Errorf("failed to load context: %v", apiErr.Msg)
	}

	if res.MaxTokensExceeded {

View on GitHub (pinned to e2d772072e)

Solutions

  1. Unwrap the inner error to identify which file failed and why, then fix that specific path/permission.
  2. Validate all paths exist and are readable before calling AutoLoadContextFiles.
  3. Decide on policy: skip bad files with warnings (collect all errors, don't fail fast) for more robust loading.
  4. Reduce the file list to known-good files when running non-interactively.
  5. Inspect the errCh aggregation loop — because it returns on first error, remaining goroutines may still be running; ensure they are drained to avoid leaks.

Example fix

// before
for range files {
    if e := <-errCh; e != nil {
        return "", fmt.Errorf("failed to load context: %v", e)
    }
}
// after
var errs []error
for range files {
    if e := <-errCh; e != nil {
        errs = append(errs, fmt.Errorf("%w", e))
    }
}
if len(errs) > 0 {
    log.Printf("skipped %d context files: %v", len(errs), errors.Join(errs...))
}
Defensive patterns

Strategy: try-catch

Validate before calling

// validate all inputs up front so goroutines never fail on obvious problems
for _, p := range files {
    if p == "" {
        return "", fmt.Errorf("empty path in file list")
    }
    if _, err := os.Stat(expandHome(p)); err != nil {
        log.Printf("warning: %s unavailable: %v", p, err)
    }
}

Try / catch

var errs []error
for range files {
    if e := <-errCh; e != nil {
        errs = append(errs, e)
    }
}
if len(errs) == len(files) {
    return "", fmt.Errorf("failed to load context: %v", errors.Join(errs...))
}
if len(errs) > 0 {
    log.Printf("partial load, skipped %d files: %v", len(errs), errors.Join(errs...))
}

Prevention

When it happens

Trigger: Any of the N goroutines sends a non-nil error on errCh — e.g. os.Stat/os.ReadFile failures, an unsupported context type for the file extension, or size accounting failing — and the collector loop hits it before all results are processed.

Common situations: Batch-loading a list of context files where at least one is missing, unreadable, or of an unsupported type; large file lists increase the odds one path is stale; concurrent goroutines racing on shared map/slice state during processing.

Related errors


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