{"record":{"id":"5dc6ce7088daf81f","repo":"can1357/oh-my-pi","slug":"vault-path-resolution-requires-a-cached-vault-r","errorCode":null,"errorMessage":"vault:// path resolution requires a cached vault root; read vault:// first or use the write tool","messagePattern":"vault:// path resolution requires a cached vault root; read vault:// first or use the write tool","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/internal-urls/vault-protocol.ts","lineNumber":432,"sourceCode":"\t\t} catch (error) {\n\t\t\tif (!isEnoent(error)) throw error;\n\t\t\tconst parent = path.dirname(current);\n\t\t\tif (parent === current) throw error;\n\t\t\tcurrent = parent;\n\t\t}\n\t}\n}\n\nexport function resolveVaultUrlToPath(input: string | InternalUrl): string {\n\tif (!isVaultEnabled()) throw new VaultDisabledError();\n\tconst parsed = parseVaultUrl(input);\n\tif (parsed.kind !== \"fs-file\" && parsed.kind !== \"fs-dir\") {\n\t\tthrow new Error(\"vault:// path resolution only supports plain filesystem paths\");\n\t}\n\n\tconst cachedRoot = getCachedVaultRoot(parsed.ref);\n\tif (!cachedRoot) {\n\t\tthrow new Error(\n\t\t\t\"vault:// path resolution requires a cached vault root; read vault:// first or use the write tool\",\n\t\t);\n\t}\n\n\tconst resolvedRoot = fs.realpathSync(cachedRoot);\n\tconst targetPath = parsed.relativePath ? path.resolve(resolvedRoot, parsed.relativePath) : resolvedRoot;\n\tensureWithinRoot(targetPath, resolvedRoot);\n\n\ttry {\n\t\tconst realTarget = fs.realpathSync(targetPath);\n\t\tensureWithinRoot(realTarget, resolvedRoot);\n\t} catch (error) {\n\t\tif (!isEnoent(error)) throw error;\n\t\tconst realParent = findExistingAncestorSync(path.dirname(targetPath), resolvedRoot);\n\t\tensureWithinRoot(realParent, resolvedRoot);\n\t}\n\n\treturn targetPath;","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/internal-urls/vault-protocol.ts#L414-L450","documentation":"resolveVaultUrlToPath needs the vault root's absolute path, which it takes from an in-process cache populated when a vault:// URL is actually read/listed (or via test hooks). If no vault has been accessed yet in this process — so getCachedVaultRoot returns nothing for the reference — the resolver throws this error telling you to read vault:// first. It is a warm-up requirement, not a permission problem.","triggerScenarios":"Calling resolveVaultUrlToPath as the very first vault operation in a fresh process (e.g. resolving `vault://MyVault/notes/a.md` without ever listing vaults or reading any vault:// URL), or referencing a named vault whose root was never cached while only the active vault was.","commonSituations":"SDK/tooling that resolves a vault link to a path before reading; multi-vault setups where the target vault name differs from the one previously accessed; tests that forgot setActiveVaultPathForTests/setVaultDirectoryForTests.","solutions":["Read `vault://_/` (or the specific vault dir) once first to populate the cache, then call resolveVaultUrlToPath.","Use the active-vault form `vault://_/path` if the active vault's root is already cached (cachedActiveVaultPath).","In tests, seed the cache via VaultProtocolHandler.setActiveVaultPathForTests() or setVaultDirectoryForTests().","If the vault name is wrong (never cached), list vaults via handler.resolve(vault://_/) and use an existing name."],"exampleFix":"// before\nconst p = resolveVaultUrlToPath(\"vault://MyVault/notes/a.md\"); // no cache yet\n// after\nawait handler.resolve(parseInternalUrl(\"vault://_/\")); // warms vault directory cache\nconst p = resolveVaultUrlToPath(\"vault://MyVault/notes/a.md\"); // now resolves","handlingStrategy":"fallback","validationCode":"// ensure a vault has been touched this process before path resolution:\nawait handler.resolve(parseInternalUrl(\"vault://_/\")); // lists vaults, populates cache\nconst p = resolveVaultUrlToPath(url);","typeGuard":"function isColdCacheError(err: unknown): boolean {\n  return err instanceof Error &&\n    err.message.includes(\"requires a cached vault root\");\n}","tryCatchPattern":"try {\n  return resolveVaultUrlToPath(url);\n} catch (err) {\n  if (isColdCacheError(err)) {\n    await handler.resolve(parseInternalUrl(\"vault://_/\")); // warm the cache\n    return resolveVaultUrlToPath(url); // retry once\n  }\n  throw err;\n}","preventionTips":["Always perform (or stub) one vault:// read/list before path-only resolution","In tests, seed with setActiveVaultPathForTests()/setVaultDirectoryForTests()","Prefer active-vault URLs (vault://_/...) when only the active vault is cached","In long-lived processes, remember the cache is in-memory and resets on restart"],"tags":["cache","initialization","state","url"],"backgroundTag":"cold-cache-unresolved-root","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}