{"record":{"id":"75c30aefd6d4ad56","repo":"JuliusBrussee/caveman","slug":"caveman-agent-invalid-memory-namespace-json-str","errorCode":null,"errorMessage":"caveman agent: invalid memory namespace ${JSON.stringify(options.namespace)}","messagePattern":"caveman agent: invalid memory namespace (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/primitives.ts","lineNumber":269,"sourceCode":"  if (!match) throw new Error(\"cave_memory_ttl_invalid\");\n  const amount = Number(match[1]);\n  const scale = match[2] === \"m\" ? 60_000 : match[2] === \"h\" ? 3_600_000 : 86_400_000;\n  const milliseconds = amount * scale;\n  if (!Number.isSafeInteger(amount) || !Number.isSafeInteger(milliseconds) || milliseconds <= 0) {\n    throw new Error(\"cave_memory_ttl_invalid\");\n  }\n  return milliseconds;\n}\n\nexport function memory(options: {\n  namespace: string;\n  provenance?: MemoryDefinition[\"provenance\"];\n  ttl: string;\n  recallBudget: number;\n  consent?: MemoryDefinition[\"consent\"];\n}): MemoryDefinition {\n  if (!/^[a-z0-9][a-z0-9_-]{0,95}$/.test(options.namespace)) {\n    throw new Error(`caveman agent: invalid memory namespace ${JSON.stringify(options.namespace)}`);\n  }\n  if (!Number.isSafeInteger(options.recallBudget) || options.recallBudget < 0) {\n    throw new Error(\"caveman agent: memory recallBudget must be a non-negative integer\");\n  }\n  try {\n    memoryTTLMilliseconds(options.ttl);\n  } catch {\n    throw new Error(\"caveman agent: memory ttl must use positive m, h, or d duration\");\n  }\n  // Fail closed at CONSTRUCTION, not at tool-call time: the durable\n  // store implements only local, single-tenant memory. A `project`/`external`\n  // provenance or a `project_shared` consent is a shared-backend contract this\n  // package does not provide, so it is refused here rather than burning a model\n  // turn to discover a config the framework already knew was unsupported.\n  const provenance = options.provenance ?? \"local\";\n  if (provenance !== \"local\") {\n    throw new Error(\"cave_memory_provenance_unsupported: only \\\"local\\\" memory is supported\");\n  }","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/primitives.ts#L251-L287","documentation":"Thrown by the memory() builder when options.namespace fails ^[a-z0-9][a-z0-9_-]{0,95}$: namespaces must start with a lowercase letter or digit, continue with lowercase letters, digits, underscore or hyphen, and be at most 96 characters. The strictness exists because the namespace becomes a store key / identifier, so uppercase, spaces, dots, slashes and unicode are refused at construction.","triggerScenarios":"Calling memory({ namespace: ... }) with values like 'My Notes', 'user/notes', 'ns.v2', 'über-memory', '' (empty), a 97+ character string, or a name starting with '-' or '_'.","commonSituations":"Deriving the namespace from a file path, project name, or free-form user input (e.g. 'My App Memory' or 'org/team/notes') instead of a slug; renaming a product and reusing the display name as the namespace.","solutions":["Slugify the namespace before calling memory(): lowercase, trim, replace runs of non-[a-z0-9_-] with '-', and truncate to 96 chars","Pick a short stable identifier by hand, e.g. 'session-notes' or 'repo-context'","Validate user-supplied namespaces with the same regex before agent construction so the error is attributed to the input, not the builder"],"exampleFix":"// before\nmemory({ namespace: 'Team Notes/2026', ttl: '7d', recallBudget: 10 });\n\n// after\nmemory({ namespace: 'team-notes-2026', ttl: '7d', recallBudget: 10 });","handlingStrategy":"validation","validationCode":"const NS_RE = /^[a-z0-9][a-z0-9_-]{0,95}$/;\nfunction normalizeNamespace(raw: string): string {\n  const slug = raw.toLowerCase().trim().replace(/[^a-z0-9_-]+/g, '-').replace(/^-+/, '').slice(0, 96);\n  if (!NS_RE.test(slug)) throw new Error(`cannot derive namespace from '${raw}'`);\n  return slug;\n}","typeGuard":"function isMemoryNamespace(value: unknown): value is string { return typeof value === 'string' && /^[a-z0-9][a-z0-9_-]{0,95}$/.test(value); }","tryCatchPattern":"try { memory({ namespace, ttl, recallBudget }); } catch (e) { if (e instanceof Error && e.message.startsWith('caveman agent: invalid memory namespace')) throw new ConfigError('namespace must be lowercase slug (<=96 chars)', { cause: e }); throw e; }","preventionTips":["Always slugify user/path-derived names before using them as namespaces","Keep namespaces short constants defined next to the memory definition","Test the slug helper with unicode, slashes and spaces"],"tags":["validation","memory","namespace","config"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}