{"record":{"id":"6a1cb35cf9e9d585","repo":"JuliusBrussee/caveman","slug":"unknown-emitcachehints-value-json-stringify-emit","errorCode":null,"errorMessage":"unknown emitCacheHints value ${JSON.stringify(emitCacheHints)}","messagePattern":"unknown emitCacheHints value (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/sdk/typescript/src/index.ts","lineNumber":1818,"sourceCode":"    items: selectedIDs.map((id) => byID.get(id)!),\n    tokensUsed,\n    tokensBefore,\n    tokensSaved,\n    deferredCount,\n    deferredIds: [...deferredIDs],\n    basis: \"inferred\"\n  };\n}\n\nconst assemblyHashLedgers = new WeakMap<Cave, Map<string, string>>();\nconst assemblyRequestHeaders = new WeakMap<object, string>();\n\nfunction assemble(cave: Cave, options: AssembleOptions): AssemblyResult {\n  const provider = options.provider.trim().toLowerCase();\n  const emitCacheHints = options.emitCacheHints ?? \"gateway\";\n  if (!options.model || !options.sessionId) throw new Error(\"assemble requires model and sessionId\");\n  if (![\"gateway\", \"self\", \"none\"].includes(emitCacheHints)) {\n    throw new Error(`unknown emitCacheHints value ${JSON.stringify(emitCacheHints)}`);\n  }\n\n  const ids = new Set<string>();\n  let ledger = assemblyHashLedgers.get(cave);\n  if (!ledger) {\n    ledger = new Map<string, string>();\n    assemblyHashLedgers.set(cave, ledger);\n  }\n  const normalized = options.slots.map((slot) => {\n    if (!slot.id || ids.has(slot.id)) throw new Error(`assembly slot id must be non-empty and unique: ${JSON.stringify(slot.id)}`);\n    ids.add(slot.id);\n    if (![\"stable\", \"session\", \"volatile\"].includes(slot.stability)) {\n      throw new Error(`assembly slot ${JSON.stringify(slot.id)} has unknown stability ${JSON.stringify(slot.stability)}`);\n    }\n    let contentJSON: string;\n    try {\n      contentJSON = canonicalJSON(slot.content);\n    } catch {","sourceCodeStart":1800,"sourceCodeEnd":1836,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/sdk/typescript/src/index.ts#L1800-L1836","documentation":"assemble() accepts an optional `emitCacheHints` option that defaults to \"gateway\" and must be one of \"gateway\", \"self\", or \"none\". Any other value — including typos and wrong-cased strings — is rejected with this Error before any assembly work. It is a strict enum guard on the cache-hint emission policy.","triggerScenarios":"Calling assemble() with `emitCacheHints` set to any string not in [\"gateway\",\"self\",\"none\"] — e.g. \"Gateway\", \"gateway-hints\", \"cache\", or a value read from config/env with unexpected casing or whitespace (note: `emitCacheHints` is used verbatim, only `provider` is lowercased).","commonSituations":"Mapping an env var like EMIT_CACHE_HINTS=Gateway straight into options; typos like \"none\" vs \"off\"; copying an option name from a different SDK version where the enum values differed; JSON config files with inconsistent casing.","solutions":["Set emitCacheHints to exactly \"gateway\", \"self\", or \"none\" (lowercase).","Normalize the value yourself before calling: `hints.trim().toLowerCase()` if it originates from config or env.","Omit the option entirely to get the \"gateway\" default.","Type the variable as the exported EmitCacheHints union so invalid values fail at compile time."],"exampleFix":"// before\ncave.assemble({ ..., emitCacheHints: process.env.HINTS as string });\n\n// after\nconst HINTS = [\"gateway\", \"self\", \"none\"] as const;\ntype Hints = typeof HINTS[number];\nconst raw = (process.env.HINTS ?? \"gateway\").toLowerCase() as Hints;\nif (!HINTS.includes(raw)) throw new Error(`bad HINTS: ${process.env.HINTS}`);\ncave.assemble({ ..., emitCacheHints: raw });","handlingStrategy":"validation","validationCode":"const EMIT_CACHE_HINTS = new Set([\"gateway\", \"self\", \"none\"]);\nfunction validHints(v) { return v === undefined || EMIT_CACHE_HINTS.has(v); }","typeGuard":"function isEmitCacheHints(v) {\n  return v === undefined || v === \"gateway\" || v === \"self\" || v === \"none\";\n}","tryCatchPattern":"try {\n  return cave.assemble(opts);\n} catch (e) {\n  if (e.message.startsWith(\"unknown emitCacheHints\")) {\n    opts.emitCacheHints = \"gateway\"; // safe default\n    return cave.assemble(opts);\n  }\n  throw e;\n}","preventionTips":["Lowercase and trim values coming from env/config before assigning emitCacheHints.","Type the field with the EmitCacheHints union so invalid literals fail compilation.","Rely on the \"gateway\" default instead of setting the option ad hoc."],"tags":["validation","enum","typescript","assembly"],"backgroundTag":"invalid-enum-value","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"}