{"record":{"id":"e7b587b405df27b9","repo":"multica-ai/multica","slug":"runtime-local-skill-discovery-timed-out","errorCode":null,"errorMessage":"runtime local skill discovery timed out","messagePattern":"runtime local skill discovery timed out","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/runtimes/local-skills.ts","lineNumber":38,"sourceCode":"// the daemon to actually run the import.\n//\n// Timeout invariant: IMPORT_POLL_TIMEOUT_MS must exceed\n// runtimeLocalSkillPendingTimeout + runtimeLocalSkillRunningTimeout\n// (server/internal/handler/runtime_local_skills.go).\n// See also IMPORT_CONCURRENCY in packages/views/.../runtime-local-skill-import-panel.tsx\n// and maxLocalSkillImportBatch in server/internal/handler/daemon.go.\nconst IMPORT_POLL_TIMEOUT_MS = 4 * 60_000; // 4 minutes\n\nexport async function resolveRuntimeLocalSkills(\n  runtimeId: string,\n): Promise<RuntimeLocalSkillsResult> {\n  const initial = await api.initiateListLocalSkills(runtimeId);\n  const start = Date.now();\n  let current = initial;\n\n  while (current.status === \"pending\" || current.status === \"running\") {\n    if (Date.now() - start > POLL_TIMEOUT_MS) {\n      throw new Error(\"runtime local skill discovery timed out\");\n    }\n    await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n    current = await api.getListLocalSkillsResult(runtimeId, initial.id);\n  }\n\n  if (current.status === \"failed\" || current.status === \"timeout\") {\n    throw new Error(current.error || \"runtime local skill discovery failed\");\n  }\n\n  return {\n    skills: current.skills ?? [],\n    supported: current.supported,\n\tmcpServers: current.mcp_servers ?? [],\n\tmcpSupported: current.mcp_supported === true,\n  };\n}\n\nexport async function resolveRuntimeLocalSkillImport(","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/packages/core/runtimes/local-skills.ts#L20-L56","documentation":"Wrap thrown by prepareHermesHome when mirrorSharedHermesHome fails. The mirror copies the shared hermes home's contents into the per-task overlay so the hermes CLI sees its expected config/assets while task-local overrides are layered on top. The overlay fails closed: a broken mirror means Hermes could run without its expected configuration, so the whole prepare aborts.","triggerScenarios":"mirrorSharedHermesHome(sharedHome, hermesHome, logger) errors — unreadable files in the shared home (permission drift), special file types it refuses to copy, destination name collisions inside the overlay, or disk exhaustion while copying.","commonSituations":"Shared home contains files owned by root or with restrictive modes the daemon cannot read; the shared home grew large (caches, many profiles) and overflows env-root; shared home on a flaky NFS mount; symlinks/sockets inside the home that the mirror rejects.","solutions":["Read the wrapped error for the failing source path; make it readable by the daemon user (chmod/chown) or remove it if it is cache/junk.","Prune large caches from the shared home or enlarge env-root storage so the mirror fits.","Stabilize the shared home's mount (avoid NFS soft mounts/timeouts) or relocate the home to local disk.","Replace unusual file types (sockets, broken symlinks) in the shared home, or point HermesSourceHome at a lean profile-specific home."],"exampleFix":"# before: shared home holds root-owned cache the daemon cannot read\n$ find ~/.hermes -not -readable -o -user root | head\n/home/user/.hermes/cache/blob   (root)\n\n# after\n$ sudo chown -R user:user /home/user/.hermes/cache\n$ rm -rf /home/user/.hermes/cache   # or just delete the cache","handlingStrategy":"validation","validationCode":"// pre-flight: every regular file in the shared home must be readable\nerr := filepath.WalkDir(sharedHome, func(p string, d fs.DirEntry, err error) error {\n    if err != nil {\n        return err\n    }\n    if d.Type().IsRegular() {\n        if fi, err := d.Info(); err == nil && fi.Mode().Perm()&0o400 == 0 {\n            return fmt.Errorf(\"unreadable file in shared home: %s\", p)\n        }\n    }\n    return nil\n})","typeGuard":null,"tryCatchPattern":"if err := prepareHermesHome(...); err != nil {\n    if strings.Contains(err.Error(), \"mirror shared hermes home\") {\n        // wrapped error names the failing source file: chmod/chown it or purge caches, then retry\n    }\n}","preventionTips":["Keep the shared hermes home free of caches, sockets, and root-owned files.","Run periodic permission audits on the shared home.","Prefer lean per-profile homes as HermesSourceHome."],"tags":["go","hermes","execenv","filesystem","mirror","permissions"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}