{"record":{"id":"6f96009de97fb581","repo":"multica-ai/multica","slug":"stat-state-marker-w","errorCode":null,"errorMessage":"stat state marker: %w","messagePattern":"stat state marker: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/daemon/execenv/hermes_home.go","lineNumber":582,"sourceCode":"\t}\n\treturn nil\n}\n\n// prepareHermesTaskLocalState migrates an overlay built by an older daemon away\n// from the shared Hermes SQLite session store. Without the marker, state.db and\n// its sidecars may be symlinks or independently copied files; neither is safe to\n// reuse as task-local state. Remove only those entries inside the generated\n// overlay, then record the migration atomically. Hermes lazily creates a fresh\n// database, and later prepares preserve it because the marker is present.\nfunc prepareHermesTaskLocalState(hermesHome string) error {\n\tmarker := filepath.Join(hermesHome, hermesTaskLocalStateMarker)\n\tif fi, err := os.Lstat(marker); err == nil {\n\t\tif !fi.Mode().IsRegular() {\n\t\t\treturn fmt.Errorf(\"state marker is not a regular file: %s\", marker)\n\t\t}\n\t\treturn nil\n\t} else if !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"stat state marker: %w\", err)\n\t}\n\n\tentries, err := os.ReadDir(hermesHome)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read overlay home: %w\", err)\n\t}\n\tfor _, entry := range entries {\n\t\tif !isHermesTaskLocalStateEntry(entry.Name()) {\n\t\t\tcontinue\n\t\t}\n\t\tpath := filepath.Join(hermesHome, entry.Name())\n\t\tif err := os.RemoveAll(path); err != nil {\n\t\t\treturn fmt.Errorf(\"remove legacy task state %s: %w\", path, err)\n\t\t}\n\t}\n\treturn writeFileAtomic(marker, []byte(\"task-local Hermes state\\n\"), 0o600)\n}\n","sourceCodeStart":564,"sourceCodeEnd":600,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/daemon/execenv/hermes_home.go#L564-L600","documentation":"prepareHermesTaskLocalState could not os.Lstat the task-local-state marker, and the error was not 'does not exist'. Unlike a missing marker (which triggers the legacy migration), an inconclusive stat means the code cannot tell whether state.db is safe to reuse, so it fails closed.","triggerScenarios":"Permission denied on the overlay dir (cannot stat entries inside it), I/O error from the underlying volume, or path-component issues (a non-directory component in the marker path).","commonSituations":"Overlay dir with restrictive ACLs after a UID change; failing disk or network volume hosting the env RootDir; security software intercepting stat calls.","solutions":["Verify the overlay dir is traversable/readable by the daemon user: `stat <hermesHome>` and `ls -la <hermesHome>`.","Fix permissions or ownership of the whole overlay dir, then retry.","If the volume is erroring, address the storage problem (remount, replace disk) — this error will recur on the same mount otherwise.","As a reset, delete the regenerable overlay dir."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if fi, err := os.Stat(filepath.Dir(marker)); err != nil {\n\treturn fmt.Errorf(\"overlay dir unavailable: %w\", err)\n} else if !fi.IsDir() {\n\treturn fmt.Errorf(\"overlay path is not a directory: %s\", filepath.Dir(marker))\n}","typeGuard":null,"tryCatchPattern":"if err := prepareHermesTaskLocalState(hermesHome); err != nil {\n\tvar pe *os.PathError\n\tif errors.As(err, &pe) && errors.Is(pe.Err, syscall.EACCES) {\n\t\tlog.Printf(\"fix permissions on %s and retry\", filepath.Dir(pe.Path))\n\t}\n\treturn err\n}","preventionTips":["Keep overlay dir ownership/permissions stable across daemon restarts.","Watch for storage-level errors on the env volume; stat failures are often the first symptom."],"tags":["filesystem","permissions","hermes","execenv"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}