{"record":{"id":"b8f78f4599326a9c","repo":"multica-ai/multica","slug":"mirror-s-w","errorCode":null,"errorMessage":"mirror %s: %w","messagePattern":"mirror (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/daemon/execenv/hermes_home.go","lineNumber":538,"sourceCode":"\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\n// nor currently mirrored from the shared home, so a shared entry deleted between\n// runs (or a Windows copy-fallback left behind) doesn't survive as stale state.\nfunc reconcileMirroredEntries(hermesHome string, mirrored map[string]struct{}) error {\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\tname := entry.Name()\n\t\tif isHermesOverlayOwnedEntry(name) {\n\t\t\tcontinue","sourceCodeStart":520,"sourceCodeEnd":556,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/daemon/execenv/hermes_home.go#L520-L556","documentation":"While mirroring one entry from the shared Hermes home into the task overlay, linkSharedHermesEntry failed for that named entry. This wraps any of the per-entry failures: removing a stale destination ('remove stale'), stat-ing the source ('stat'), or creating the symlink itself (createDirLink/createFileLink, plain os.Symlink on POSIX, copy fallback on Windows). The %s names the entry (e.g. .env, auth.json).","triggerScenarios":"A specific entry in the shared home is unreadable or its existing overlay counterpart is undeletable: dst left root-owned from a previous privileged run; Windows symlink creation without Developer Mode/privilege; EEXIST race with a concurrent task reusing the same overlay; source entry is a symlink loop.","commonSituations":"Mixed-privilege daemons (some tasks ran as root, later ones as a normal user); Windows hosts without symlink privilege; two daemon replicas preparing the same env RootDir concurrently; an antivirus/backup tool briefly holding the entry.","solutions":["Inspect the named entry in both the shared home and the overlay dir: `ls -la` both paths, look for root-owned or read-only leftovers.","Delete the stale overlay entry (or the whole env overlay dir under RootDir/hermes-home) so the next prepare recreates it cleanly.","On Windows, enable Developer Mode or run the daemon with symlink privilege so os.Symlink works.","Ensure only one daemon instance prepares a given env at a time; two writers racing on one overlay is not supported."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := mirrorSharedHermesHome(sharedHome, hermesHome, logger); err != nil {\n\tif strings.HasPrefix(err.Error(), \"mirror \") {\n\t\t// one entry is bad: wipe the regenerable overlay and retry once\n\t\tif rmErr := os.RemoveAll(hermesHome); rmErr == nil {\n\t\t\treturn mirrorSharedHermesHome(sharedHome, hermesHome, logger)\n\t\t}\n\t}\n\treturn err\n}","preventionTips":["Ensure Windows symlink privilege (Developer Mode) when overlays live on Windows.","Never share one env RootDir between concurrently running daemons.","Keep overlay dirs owned by the daemon's own UID."],"tags":["filesystem","symlink","windows","hermes","execenv"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}