multica-ai/multica · error
create hermes memory staging dir in %s: %w
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.
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)
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 %s into %s: %w
- create temp for %s: %w
- write temp for %s: %w
- remove stale memories path %s: %w
- read hermes memory store %s: %w
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/3f4fc4b8f746cc38.
Report an issue: GitHub.