{"record":{"id":"fa576ac61f82cbde","repo":"JuliusBrussee/caveman","slug":"cave-memory-shared-backend-unavailable","errorCode":"cave_memory_shared_backend_unavailable","errorMessage":"cave_memory_shared_backend_unavailable","messagePattern":"cave_memory_shared_backend_unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/runtime.ts","lineNumber":3116,"sourceCode":"    },\n  };\n}\n\nfunction validEngineTokenCount(value: unknown): number | undefined {\n  return Number.isSafeInteger(value) && Number(value) >= 0 ? Number(value) : undefined;\n}\n\nfunction localMemoryTools(\n  definition: NonNullable<AgentDefinition[\"memory\"]>,\n  agentId: string,\n  config: MemoryStoreConfig | undefined,\n): AgentTool<TSchema>[] {\n  // Defense in depth: memory() already rejects a non-local provenance/consent at\n  // construction, but a hand-built MemoryDefinition must still fail\n  // BEFORE the run spends — not inside a tool call — so this throws at tool\n  // setup, never at execute time.\n  if (definition.provenance !== \"local\" || definition.consent !== \"local_only\") {\n    throw new Error(\"cave_memory_shared_backend_unavailable\");\n  }\n  // Resolved once so a validation failure surfaces at setup, and every entry is\n  // scoped by (tenant, agentId, namespace): two AgentDefinitions declaring the\n  // same namespace in one process write to different files and never bleed.\n  const filePath = memoryFilePath(config, agentId, definition.namespace);\n  const ttl = memoryTTLMilliseconds(definition.ttl);\n  const recall: AgentTool<TSchema> = {\n    name: \"cave_memory_search\",\n    label: \"cave_memory_search\",\n    description: \"Recall relevant local memory from declared namespace. Returns bounded local evidence only.\",\n    parameters: Type.Object({ query: Type.String() }),\n    executionMode: \"parallel\",\n    async execute(_toolCallId, params) {\n      const query = (params as { query: string }).query;\n      const now = Date.now();\n      // Eviction on read: a memory past its declared ttl is neither returned nor\n      // kept — the durable set is rewritten with only the live entries.\n      const live = await mutateMemories(filePath, (entries) =>","sourceCodeStart":3098,"sourceCodeEnd":3134,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/runtime.ts#L3098-L3134","documentation":"`localMemoryTools` throws `cave_memory_shared_backend_unavailable` at tool-setup time when an `AgentDefinition.memory` block does not declare `provenance: \"local\"` and `consent: \"local_only\"`. This runtime only implements a local file-backed memory store; any shared/remote memory backend configuration is rejected before the run starts (before any spend), as defense in depth on top of the `memory()` builder check, so hand-built `MemoryDefinition` objects also fail closed.","triggerScenarios":"Passing a hand-built `MemoryDefinition` with `provenance` other than `\"local\"` or `consent` other than `\"local_only\"` in an `AgentDefinition`, bypassing the `memory()` builder's own validation.","commonSituations":"Constructing agent definitions programmatically from JSON/config files that carry shared-backend flags; copying a definition snippet written for a backend-supporting deployment; typos like `provenance: \"Local\"` or `consent: \"localOnly\"`.","solutions":["Set `provenance: \"local\"` and `consent: \"local_only\"` on the memory definition (or use the `memory()` builder helper, which validates this).","If you intended a shared memory backend, this runtime does not support one — implement storage in your own tools instead of configuring it here.","Fix string casing/typos so both fields match the exact enum values."],"exampleFix":"// before\nconst def = { memory: { namespace: \"notes\", provenance: \"shared\", consent: \"local_only\" } };\n// after\nconst def = { memory: { namespace: \"notes\", provenance: \"local\", consent: \"local_only\" } };","handlingStrategy":"validation","validationCode":"function isLocalMemory(m: { provenance: string; consent: string }): boolean {\n  return m.provenance === \"local\" && m.consent === \"local_only\";\n}\nif (def.memory && !isLocalMemory(def.memory)) throw new Error(\"memory must be local/local_only\");","typeGuard":"const isLocalMemoryDef = (m: MemoryDefinition): m is MemoryDefinition & { provenance: \"local\"; consent: \"local_only\" } =>\n  m.provenance === \"local\" && m.consent === \"local_only\";","tryCatchPattern":"try {\n  await runAgent(def);\n} catch (e) {\n  if ((e as Error).message === \"cave_memory_shared_backend_unavailable\") {\n    console.error(\"AgentDefinition.memory must be provenance=local, consent=local_only\");\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Build memory config with the `memory()` builder instead of hand-writing MemoryDefinition objects.","Validate agent definitions loaded from JSON/config against the exact enum strings before running.","Remember this runtime only supports local file-backed memory — never configure shared backends here."],"tags":["memory","config","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}