multica-ai/multica · error
create hermes memory staging dir in
Error message
create hermes memory staging dir in %s: %w
What it means
Returned by newHermesStoreStaging when os.MkdirTemp fails to create the dot-prefixed scratch dir (.<store>.migrating-*) inside the store's parent. This staging dir is what the migration copies into before one atomic rename publishes it, so failure stops migration before anything is touched.
Solutions
- Freeze space/inodes on the volume containing the profile dir and retry the task.
- Fix write permissions on <profile>/hermes-state/<agent> for the daemon user.
- If it recurs under many concurrent tasks, stagger task starts to reduce simultaneous migrations.
Defensive patterns
Strategy: retry
Validate before calling
// Cheap canary: if a temp dir can be made, MkdirTemp will likely succeed.
if _, err := os.MkdirTemp(parent, ".canary-"); err != nil {
return fmt.Errorf("staging area unusable: %w", err)
} else { os.Remove(canary) } Try / catch
if _, err := newHermesStoreStaging(storeDir); err != nil && isTransient(err) {
// EMFILE/ENOSPC class: back off once, then retry
time.Sleep(time.Second)
_, err = newHermesStoreStaging(storeDir)
} Prevention
- Cap simultaneous task starts to avoid temp-dir handle storms
- Monitor ENOSPC/EMFILE in daemon logs
- Keep migrations off read-only mounts
When it happens
Trigger: os.MkdirTemp in the store parent fails: parent not writable (EACCES), disk full (ENOSPC), too many open files (EMFILE) under heavy concurrency, or file-name pattern issues on exotic filesystems.
Common situations: Disk-full on the profile volume during an upgrade with large memories; read-only mount; heavy concurrent task starts exhausting temp-dir handles.
Related errors
- migrate task-local hermes memory
- clear empty hermes store
- create hermes memory store parent
- create temp for
- read hermes memory store
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/3f4fc4b8f746cc38.
Report an issue: GitHub.
Appendix: source
Thrown at server/internal/daemon/execenv/hermes_memory.go:268
return nil
}
// newHermesStoreStaging creates the scratch directory a store migration copies
// into. It is a sibling of the store so the promoting rename stays within one
// filesystem, and dot-prefixed so it is obvious it is not a store of its own.
// Shared by the memory migration here and the session-database migration in
// hermes_sessions.go: both delete their source once the copy reports success,
// so both need the same all-or-nothing publish.
// MkdirTemp already creates it 0700, the same mode the store itself is created
// with, so there is no follow-up chmod that could fail and strand it.
func newHermesStoreStaging(storeDir string) (string, error) {
parent := filepath.Dir(storeDir)
if err := os.MkdirAll(parent, 0o700); err != nil {
return "", fmt.Errorf("create hermes memory store parent %s: %w", parent, err)
}
staging, err := os.MkdirTemp(parent, "."+filepath.Base(storeDir)+".migrating-")
if err != nil {
return "", fmt.Errorf("create hermes memory staging dir in %s: %w", parent, err)
}
return staging, nil
}
// promoteHermesStoreStaging publishes a fully-copied staging dir as the store,
// reporting whether this caller won. The empty store dir (if any) is removed
// first: os.Remove only succeeds on an empty directory, so a store another task
// already populated makes this a no-op, and Windows rejects a rename onto an
// existing directory outright.
//
// Losing the race is not an error — the winner's store holds the same agent's
// state — but it has to be positively confirmed, never inferred from any
// failure. The caller deletes the source directory whenever this returns
// (false, nil), so a permission error, a read-only filesystem or a Windows
// sharing violation must fail closed instead of passing for "someone else
// published".
//
// published answers "did a competitor already publish real state here?" and isView on GitHub (pinned to 2c0912b6ec)