can1357/oh-my-pi · error

Cache benchmark prefix template is missing its raw prefix pl

Error message

Cache benchmark prefix template is missing its raw prefix placeholder

What it means

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.

Source

Thrown at packages/coding-agent/src/cli/bench-cli.ts:436

}

function truncateUtf8(text: string, maxBytes: number): string {
	const bytes = UTF8_ENCODER.encode(text);
	const end = truncateUtf8ByteLength(bytes, maxBytes);
	return end === bytes.byteLength ? text : UTF8_DECODER.decode(bytes.subarray(0, end));
}

function generatedCachePrefix(bytes: number): string {
	return truncateUtf8(CACHE_PREFIX_CHUNK.repeat(Math.ceil(bytes / CACHE_PREFIX_CHUNK_BYTES)), bytes);
}

function renderCacheBenchmarkPrefix(prefix: string, namespace: string): string {
	const rendered = prompt.render(cachePrefixTemplate, {
		prefix: CACHE_PREFIX_PLACEHOLDER,
		namespace,
	});
	if (!rendered.includes(CACHE_PREFIX_PLACEHOLDER)) {
		throw new Error("Cache benchmark prefix template is missing its raw prefix placeholder");
	}
	// Render the static wrapper first, then inject caller bytes so prompt
	// normalization cannot trim spaces or collapse blank lines in prefix files.
	// Function replacer: a prefix containing `$&`/`$'`/`` $` `` must not be
	// expanded as a string-replacement pattern.
	return rendered.replace(CACHE_PREFIX_PLACEHOLDER, () => prefix);
}

async function resolveCachePrefix(
	flags: BenchCommandArgs["flags"],
	readTextFile: (path: string, maxBytes: number) => Promise<string>,
): Promise<string> {
	const bytes = normalizePositiveInteger("cache-prefix-bytes", flags.cachePrefixBytes, DEFAULT_CACHE_PREFIX_BYTES);
	const prefix = flags.cachePrefixFile
		? await readTextFile(flags.cachePrefixFile, bytes)
		: generatedCachePrefix(bytes);
	return truncateUtf8(prefix, bytes);
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Restore the raw prefix placeholder token in the cache prefix template file.
  2. Verify the placeholder name matches CACHE_PREFIX_PLACEHOLDER exactly (no renaming/escaping).
  3. Re-run the benchmark after the template fix.

Example fix

// before (template)
You are a helpful assistant.
// after (template)
{{prefix}}
You are a helpful assistant.
Defensive patterns

Strategy: validation

Validate before calling

const tpl = await Bun.file(cachePrefixPath).text();
if (!tpl.includes("{{prefix}}")) throw new Error("prefix template lost its placeholder");

Type guard

function templateHasPlaceholder(t: string, p: string): boolean {
  return t.includes(p);
}

Try / catch

try {
  const prefix = stablePrefix(bytes, ns);
} catch (err) {
  if (String(err).includes("missing its raw prefix placeholder")) {
    logger.error("cache prefix template is broken; restore the placeholder token");
  }
  throw err;
}

Prevention

When it happens

Trigger: Editing/misconfiguring the cache prefix prompt template so it no longer contains the CACHE_PREFIX_PLACEHOLDER, or prompt.render stripping the placeholder token.

Common situations: A contributor edits the cache prefix .md template and removes/renames the placeholder; a templating change that HTML-escapes or trims the token.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/297f96a685b8f076. Report an issue: GitHub.