multica-ai/multica · error
create temp for %s: %w
Error message
create temp for %s: %w
What it means
writeFileAtomic could not create a temp file in the destination directory (os.CreateTemp with prefix .hermes-tmp-*). Every derived-file write (config.yaml, marker, memory store sidecars) goes through this atomic-write helper; failure here usually means the destination directory is missing, unwritable, or the filesystem is exhausted.
Source
Thrown at server/internal/daemon/execenv/hermes_home.go:917
// marshalYAMLToFile renders a YAML node to dst as a 0600 file (it can hold
// inline secrets) via atomic replace.
func marshalYAMLToFile(doc *yaml.Node, dst string) error {
out, err := yaml.Marshal(doc)
if err != nil {
return fmt.Errorf("marshal hermes config: %w", err)
}
return writeFileAtomic(dst, out, 0o600)
}
// writeFileAtomic writes data to a temp file in the destination directory with
// the given perms, then renames it over dst — so readers never see a partial
// file and a prior file's looser permissions are replaced.
func writeFileAtomic(dst string, data []byte, perm os.FileMode) error {
dir := filepath.Dir(dst)
tmp, err := os.CreateTemp(dir, ".hermes-tmp-*")
if err != nil {
return fmt.Errorf("create temp for %s: %w", dst, err)
}
tmpName := tmp.Name()
defer os.Remove(tmpName) // no-op once renamed
if _, err := tmp.Write(data); err != nil {
tmp.Close()
return fmt.Errorf("write temp for %s: %w", dst, err)
}
if err := tmp.Chmod(perm); err != nil {
tmp.Close()
return fmt.Errorf("chmod temp for %s: %w", dst, err)
}
if err := tmp.Close(); err != nil {
return fmt.Errorf("close temp for %s: %w", dst, err)
}
if err := os.Rename(tmpName, dst); err != nil {
return fmt.Errorf("rename temp to %s: %w", dst, err)
}
return nilView on GitHub (pinned to 2c0912b6ec)
Solutions
- Check df -h and quota on the filesystem holding the destination path; free space or raise the quota.
- Verify the destination directory exists and is writable by the daemon user; recreate/fix as needed.
- Check the daemon's open-FD count (`ls /proc/<pid>/fd | wc -l`) and restart it if leaking.
- If the FS remounted read-only after an error, address the disk problem and remount.
Defensive patterns
Strategy: validation
Validate before calling
if err := ensureWritableDir(filepath.Dir(dst)); err != nil {
return fmt.Errorf("cannot write to %s: %w", filepath.Dir(dst), err)
}
func ensureWritableDir(dir string) error {
fi, err := os.Stat(dir)
if err != nil {
return err
}
if !fi.IsDir() {
return fmt.Errorf("not a directory: %s", dir)
}
probe, perr := os.CreateTemp(dir, ".probe-*")
if perr != nil {
return perr
}
probe.Close()
os.Remove(probe.Name())
return nil
} Try / catch
if err := writeFileAtomic(dst, data, 0o600); err != nil {
var pe *os.PathError
if errors.As(err, &pe) && (errors.Is(pe.Err, syscall.ENOSPC) || errors.Is(pe.Err, syscall.EROFS)) {
log.Printf("storage problem on %s: %v — free space / check mount", filepath.Dir(dst), pe.Err)
}
return err
} Prevention
- Alert on disk usage of the env/workspaces volume before it hits 100%.
- Validate writability of destination dirs at daemon startup, not mid-task.
When it happens
Trigger: Destination dir was deleted concurrently; daemon lacks write permission on the overlay/config dir; ENOSPC (disk/quota full); EMFILE (too many open files); read-only filesystem.
Common situations: Disk-full CI boxes or containers where env RootDir lives on a small volume; overlay dirs wiped by GC mid-prepare; overlay on a read-only mount after a disk error; long-running daemon leaking file descriptors.
Related errors
- runtime local skill import timed out
- write temp for %s: %w
- mint PAT: target API URL not set
- mint PAT: response missing token
- daemon profile is not resolved yet; token sync skipped
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/9838f8777938fdbb.
Report an issue: GitHub.