{"record":{"id":"297f96a685b8f076","repo":"can1357/oh-my-pi","slug":"cache-benchmark-prefix-template-is-missing-its-raw","errorCode":null,"errorMessage":"Cache benchmark prefix template is missing its raw prefix placeholder","messagePattern":"Cache benchmark prefix template is missing its raw prefix placeholder","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/cli/bench-cli.ts","lineNumber":436,"sourceCode":"}\n\nfunction truncateUtf8(text: string, maxBytes: number): string {\n\tconst bytes = UTF8_ENCODER.encode(text);\n\tconst end = truncateUtf8ByteLength(bytes, maxBytes);\n\treturn end === bytes.byteLength ? text : UTF8_DECODER.decode(bytes.subarray(0, end));\n}\n\nfunction generatedCachePrefix(bytes: number): string {\n\treturn truncateUtf8(CACHE_PREFIX_CHUNK.repeat(Math.ceil(bytes / CACHE_PREFIX_CHUNK_BYTES)), bytes);\n}\n\nfunction renderCacheBenchmarkPrefix(prefix: string, namespace: string): string {\n\tconst rendered = prompt.render(cachePrefixTemplate, {\n\t\tprefix: CACHE_PREFIX_PLACEHOLDER,\n\t\tnamespace,\n\t});\n\tif (!rendered.includes(CACHE_PREFIX_PLACEHOLDER)) {\n\t\tthrow new Error(\"Cache benchmark prefix template is missing its raw prefix placeholder\");\n\t}\n\t// Render the static wrapper first, then inject caller bytes so prompt\n\t// normalization cannot trim spaces or collapse blank lines in prefix files.\n\t// Function replacer: a prefix containing `$&`/`$'`/`` $` `` must not be\n\t// expanded as a string-replacement pattern.\n\treturn rendered.replace(CACHE_PREFIX_PLACEHOLDER, () => prefix);\n}\n\nasync function resolveCachePrefix(\n\tflags: BenchCommandArgs[\"flags\"],\n\treadTextFile: (path: string, maxBytes: number) => Promise<string>,\n): Promise<string> {\n\tconst bytes = normalizePositiveInteger(\"cache-prefix-bytes\", flags.cachePrefixBytes, DEFAULT_CACHE_PREFIX_BYTES);\n\tconst prefix = flags.cachePrefixFile\n\t\t? await readTextFile(flags.cachePrefixFile, bytes)\n\t\t: generatedCachePrefix(bytes);\n\treturn truncateUtf8(prefix, bytes);\n}","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cli/bench-cli.ts#L418-L454","documentation":"renderCacheBenchmarkPrefix renders the cache prefix template with a placeholder token, then injects the caller's prefix bytes via a function replacer (so regex metacharacters in the prefix aren't expanded). It throws if the placeholder survived rendering — meaning the template failed to consume the raw prefix slot, so the caller's prefix bytes were never injected and the benchmark prefix would be wrong.","triggerScenarios":"Editing/misconfiguring the cache prefix prompt template so it no longer contains the CACHE_PREFIX_PLACEHOLDER, or prompt.render stripping the placeholder token.","commonSituations":"A contributor edits the cache prefix .md template and removes/renames the placeholder; a templating change that HTML-escapes or trims the token.","solutions":["Restore the raw prefix placeholder token in the cache prefix template file.","Verify the placeholder name matches CACHE_PREFIX_PLACEHOLDER exactly (no renaming/escaping).","Re-run the benchmark after the template fix."],"exampleFix":"// before (template)\nYou are a helpful assistant.\n// after (template)\n{{prefix}}\nYou are a helpful assistant.","handlingStrategy":"validation","validationCode":"const tpl = await Bun.file(cachePrefixPath).text();\nif (!tpl.includes(\"{{prefix}}\")) throw new Error(\"prefix template lost its placeholder\");","typeGuard":"function templateHasPlaceholder(t: string, p: string): boolean {\n  return t.includes(p);\n}","tryCatchPattern":"try {\n  const prefix = stablePrefix(bytes, ns);\n} catch (err) {\n  if (String(err).includes(\"missing its raw prefix placeholder\")) {\n    logger.error(\"cache prefix template is broken; restore the placeholder token\");\n  }\n  throw err;\n}","preventionTips":["Add a unit test asserting the placeholder survives prompt.render","Never hand-edit the placeholder token in the template","Review template changes with the cache benchmark smoke run"],"tags":["benchmark","template","internal-invariant"],"backgroundTag":"template-placeholder-missing","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}