sipeed/picoclaw · error
write result: %w
Error message
write result: %w
What it means
os.WriteFile failure while persisting an individual eval result file eval_<mode>_<sampleID>.json under outDir. The error wraps the underlying syscall (permission, ENOSPC, ENAMETOOLONG, ENOENT if the directory vanished mid-run). Because the loop aborts on first failure, later samples are not written.
Source
Thrown at cmd/membench/eval.go:278
ByCategory: byCat,
TotalQuestions: len(qaResults),
ValidF1Count: validF1Count,
}
}
// SaveResults writes per-sample eval results to JSON files.
func SaveResults(results []EvalResult, outDir string) error {
if err := os.MkdirAll(outDir, 0o755); err != nil {
return fmt.Errorf("create output dir: %w", err)
}
for _, r := range results {
path := filepath.Join(outDir, fmt.Sprintf("eval_%s_%s.json", r.Mode, r.SampleID))
data, err := json.MarshalIndent(r, "", " ")
if err != nil {
return fmt.Errorf("marshal result: %w", err)
}
if err := os.WriteFile(path, data, 0o644); err != nil {
return fmt.Errorf("write result: %w", err)
}
}
return nil
}
// SaveAggregated writes a combined results.json with all modes.
func SaveAggregated(results []EvalResult, outDir string) error {
byMode := map[string][]EvalResult{}
for _, r := range results {
byMode[r.Mode] = append(byMode[r.Mode], r)
}
aggMap := map[string]AggMetrics{}
for mode, modeResults := range byMode {
aggMap[mode] = computeModeAgg(modeResults)
}
data, err := json.MarshalIndent(aggMap, "", " ")View on GitHub (pinned to 49183d7e8d)
Solutions
- Check df/space on the output volume and free room, then rerun (ingestion is idempotent via existing-conversation check)
- Sanitize SampleID before it reaches the filename: strip '/' and length-cap it
- Verify outDir still exists and is writable immediately before the run
- Write to a local directory first and sync results off-box, instead of writing directly to network storage
Example fix
// before
path := filepath.Join(outDir, fmt.Sprintf("eval_%s_%s.json", r.Mode, r.SampleID))
// after
safeID := strings.Map(func(c rune) rune {
if c == '/' || c == os.PathSeparator { return '_' }
return c
}, r.SampleID)
path := filepath.Join(outDir, fmt.Sprintf("eval_%s_%s.json", r.Mode, safeID)) Defensive patterns
Strategy: try-catch
Validate before calling
if fi, err := os.Stat(outDir); err == nil && !fi.IsDir() {
return fmt.Errorf("%s exists and is a file", outDir)
}
// plus a write-probe as in the mkdir check Try / catch
var pathErr *fs.PathError
if errors.As(err, &pathErr) {
switch {
case errors.Is(pathErr.Err, syscall.ENOSPC):
log.Printf("disk full writing %s; freeing space", pathErr.Path)
case errors.Is(pathErr.Err, syscall.ENAMETOOLONG):
log.Printf("filename too long for sample %s", r.SampleID)
default:
log.Printf("write failed: %v", pathErr)
}
} Prevention
- Sanitize SampleID (strip path separators, cap length) before it enters a filename
- Monitor disk space for long eval sweeps; they write one JSON per sample per mode
- Write locally, sync remotely — avoid NFS as the direct output target
- Run ingestion idempotently: rerun resumes and rewrites missing files
When it happens
Trigger: Disk fills up mid-run; outDir deleted or unmounted between MkdirAll and WriteFile; SampleID containing '/' or path separators creating an invalid path; filename exceeding NAME_MAX (255) for long sample IDs; SELinux/AppArmor denying writes.
Common situations: Large eval sweeps filling a small tmpfs; container whose volume is rotated mid-run; sample IDs with characters that are legal in the source dataset but illegal in filenames.
Related errors
- create output dir: %w
- Failed to save launcher config: %v
- Failed to save catalogs: %v
- marshal result: %w
- create seahorse engine: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/7261ad4a2950b445.
Report an issue: GitHub.