multica-ai/multica · error
close copy
Error message
close %s copy %s: %w
What it means
The destination file is closed explicitly after io.Copy so that write-back failures (delayed ENOSPC, flush errors) are returned instead of being swallowed by the deferred Close. Seeing this error means data believed written did not actually reach stable storage.
Solutions
- Check and free disk space on the task home volume
- Retry after resolving the underlying I/O condition
- Check system logs for device errors
Defensive patterns
Strategy: retry
Try / catch
if err := materialiseInCodexHome(...); err != nil {
if errors.Is(err, syscall.ENOSPC) {
// close-time flush failure: space was exhausted during copy
}
} Prevention
- Treat close errors as real write failures — never ignore them
- Reserve headroom on volumes used for task homes
When it happens
Trigger: Buffered write flushed at close time hits ENOSPC or an I/O error; filesystem with delayed allocation reports failure only on close/fsync.
Common situations: Disk that was nearly full at copy time; failing drive; overlay filesystem in a container.
Related errors
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/9703ee39b714fc65.
Report an issue: GitHub.
Appendix: source
Thrown at server/internal/daemon/execenv/codex_home.go:1048
in, err := os.Open(src)
if err != nil {
return fmt.Errorf("open %s %s: %w", key, src, err)
}
defer in.Close()
out, err := root.OpenFile(relPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o644)
if err != nil {
return fmt.Errorf("create %s copy %s: %w", key, relPath, err)
}
defer out.Close()
if _, err := io.Copy(out, in); err != nil {
return fmt.Errorf("copy %s %s to %s: %w", key, src, relPath, err)
}
// Close explicitly so a deferred write-back failure cannot be swallowed; the
// deferred Close then no-ops.
if err := out.Close(); err != nil {
return fmt.Errorf("close %s copy %s: %w", key, relPath, err)
}
return nil
}
// syncCodexModelsCache seeds models_cache.json once for a fresh task home and
// binds it to the shared provider/catalog configuration. Codex can replace the
// task-local cache after startup, so an unchanged binding preserves whatever
// the task last wrote rather than restoring a potentially stale shared copy.
//
// A changed or missing binding makes an existing cache unsafe: Codex's cache
// format (as of 0.144.x) records the client version and fetch time but not the
// provider identity. Reusing that cache after config.toml switches providers
// can therefore pair provider B with provider A's model catalog. Drop it and
// let Codex fetch a catalog for the new effective configuration. We
// deliberately do not seed the shared cache in this case because it carries
// the same provider-identity ambiguity.
func syncCodexModelsCache(codexHome, sharedHome string, freshHome bool) error {
fingerprint, err := codexModelsCacheConfigFingerprint(sharedHome)View on GitHub (pinned to 2c0912b6ec)