{"record":{"id":"68bb7ada481af2b2","repo":"multica-ai/multica","slug":"read-shared-home-w","errorCode":null,"errorMessage":"read shared home: %w","messagePattern":"read shared home: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/daemon/execenv/hermes_home.go","lineNumber":527,"sourceCode":"\treturn strings.TrimSpace(s[:eq])\n}\n\n// mirrorSharedHermesHome symlinks every top-level entry of the shared ~/.hermes/\n// into the per-task home except the overlay-owned entries, then reconciles the\n// destination so entries removed from the shared home (or left over from a prior\n// reuse) don't linger as readable stale state. Symlinks share state with the\n// user's real home (auth/OAuth refreshes propagate, no credential copy lingers\n// in task scratch). The shared home itself is never written — we only read it\n// and create links pointing into it.\nfunc mirrorSharedHermesHome(sharedHome, hermesHome string, logger *slog.Logger) error {\n\tentries, err := os.ReadDir(sharedHome)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\t// No shared home to mirror. The derived config + bound skills still\n\t\t\t// give Hermes a working home, so this is not fatal on its own.\n\t\t\treturn reconcileMirroredEntries(hermesHome, nil)\n\t\t}\n\t\treturn fmt.Errorf(\"read shared home: %w\", err)\n\t}\n\tmirrored := make(map[string]struct{}, len(entries))\n\tfor _, entry := range entries {\n\t\tname := entry.Name()\n\t\tif isHermesOverlayOwnedEntry(name) {\n\t\t\tcontinue\n\t\t}\n\t\tsrc := filepath.Join(sharedHome, name)\n\t\tdst := filepath.Join(hermesHome, name)\n\t\tif err := linkSharedHermesEntry(src, dst); err != nil {\n\t\t\treturn fmt.Errorf(\"mirror %s: %w\", name, err)\n\t\t}\n\t\tmirrored[name] = struct{}{}\n\t}\n\treturn reconcileMirroredEntries(hermesHome, mirrored)\n}\n\n// reconcileMirroredEntries removes overlay entries that are neither overlay-owned","sourceCodeStart":509,"sourceCodeEnd":545,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/daemon/execenv/hermes_home.go#L509-L545","documentation":"mirrorSharedHermesHome could not list the shared Hermes home (os.ReadDir) and the failure was not 'does not exist'. The daemon builds each task's Hermes overlay by symlinking entries out of the user's real home, so an unreadable source home aborts overlay construction. The wrapped error is the underlying *PathError (permission denied, not-a-directory, I/O error).","triggerScenarios":"Running a task whose resolved HERMES_HOME (or the platform default ~/.hermes, %LOCALAPPDATA%\\hermes on Windows) exists but cannot be listed: mode 000, owned by another user, the path is actually a file, or the filesystem errors (NFS stale handle, detached volume).","commonSituations":"Daemon runs as a different user/service account than the one owning ~/.hermes; HERMES_HOME pointed at a file or a OneDrive/enterprise share with restricted ACLs; home directory on a network mount that went away mid-run.","solutions":["Check the resolved shared home: run the daemon env with HERMES_HOME printed, verify `ls -la <sharedHome>` works as the daemon user.","Fix ownership/permissions on the shared home (chown/chmod so the daemon's UID can read it).","If HERMES_HOME points at a wrong path (file, mountpoint), point it at the real Hermes home or unset it to use the platform default.","If the volume is flaky (NFS/network share), remount or move the Hermes home to local disk and retry the task."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if fi, err := os.Stat(sharedHome); err != nil || !fi.IsDir() {\n\treturn fmt.Errorf(\"shared hermes home unusable: %v\", err)\n}\nif entries, err := os.ReadDir(sharedHome); err != nil {\n\treturn fmt.Errorf(\"shared hermes home not listable: %w\", err)\n} else {\n\t_ = entries // readable\n}","typeGuard":null,"tryCatchPattern":"if err := mirrorSharedHermesHome(sharedHome, hermesHome, logger); err != nil {\n\tvar pe *os.PathError\n\tif errors.As(err, &pe) {\n\t\tlog.Printf(\"shared home path failure at %s: %v\", pe.Path, pe.Err)\n\t}\n\treturn err // overlay cannot be trusted if the source home is unreadable\n}","preventionTips":["Run the daemon as the user who owns the Hermes home, or grant that UID read access.","Smoke-test env setup with `ls -la $HERMES_HOME` under the daemon account.","Keep the Hermes home on local, healthy disk rather than network shares."],"tags":["filesystem","permissions","hermes","daemon","execenv"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}