{"record":{"id":"b1efcaeddfa8b2fe","repo":"nodejs/node","slug":"expected-d-and-got-d-replacement-s-for-pattern","errorCode":null,"errorMessage":"Expected %d and got %d replacement(s) for pattern: %s","messagePattern":"Expected (.+?) and got (.+?) replacement\\(s\\) for pattern: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"deps/v8/tools/gen-keywords-gen-h.py","lineNumber":42,"sourceCode":"\n\ndef call_with_input(cmd: List[Union[str, Path]], input_string: str = \"\") -> str:\n  p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)\n  stdout, _ = p.communicate(input_string.encode())\n  retcode = p.wait()\n  if retcode != 0:\n    raise subprocess.CalledProcessError(retcode, cmd)\n  return stdout.decode()\n\n\ndef checked_sub(pattern: Union[str, re.Pattern[str]],\n                sub: str,\n                out: str,\n                count: int = 1,\n                flags: int = 0) -> str:\n  out, n = re.subn(pattern, sub, out, flags=flags)\n  if n != count:\n    raise Exception(\"Expected %d and got %d replacement(s) for pattern: %s\" %\n                    (count, n, pattern))\n  return out\n\n\ndef change_sizet_to_int(out: str) -> str:\n  # Literal buffer lengths are given as ints, not size_t\n  return checked_sub(r'\\bsize_t\\b', 'int', out, count=4)\n\n\ndef drop_line_directives(out: str) -> str:\n  # #line causes gcov issue, so drop it\n  return re.sub(r'^#\\s*line .*$\\n', '', out, flags=re.MULTILINE)\n\n\ndef trim_and_dcheck_char_table(out: str) -> str:\n  # Potential keyword strings are known to be lowercase ascii, so chop off the\n  # rest of the table and mask out the char\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/v8/tools/gen-keywords-gen-h.py#L24-L60","documentation":"gen-keywords-gen-h.py uses checked_sub() as an assertion that a regex substitution hits an exact expected count of replacements. It runs re.subn and, if the number of matches differs from `count`, raises an Exception showing expected vs. actual. Callers like change_sizet_to_int expect exactly 4 `size_t` occurrences; the guard detects that the upstream-generated input (from a gperf/m4 pipeline) has drifted in structure.","triggerScenarios":"The generated keyword header intermediate contains a different number of the pattern than the code asserts (e.g. change_sizet_to_int wants count=4 `size_t` tokens but a new V8 version produces 3 or 5). Any upstream template change to the keyword table generation breaks the invariant.","commonSituations":"Bumping V8 / the keyword grammar so gperf output shape changes; a partial regeneration that omitted or duplicated a section; editing the codegen template without updating the count parameter.","solutions":["Re-read the generated intermediate file and count the actual pattern occurrences, then update the checked_sub count= argument to match the new reality.","Regenerate the full keyword pipeline from scratch (run the gperf step) to ensure the input is not stale or partial.","If the drift is unintended, find the upstream change that altered the number of `size_t` (or other pattern) tokens and reconcile it."],"exampleFix":"// before\ndef change_sizet_to_int(out: str) -> str:\n  return checked_sub(r'\\bsize_t\\b', 'int', out, count=4)\n// after\ndef change_sizet_to_int(out: str) -> str:\n  return checked_sub(r'\\bsize_t\\b', 'int', out, count=3)","handlingStrategy":"validation","validationCode":"import re\n_count = len(re.findall(r'\\bsize_t\\b', generated_out))\nif _count != 4:\n    sys.exit(f'codegen invariant broken: found {_count} size_t tokens, expected 4; upstream template drifted')","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Treat checked_sub counts as codegen invariants: when upgrading V8/keyword grammar, re-count and update count= immediately.","Regenerate the full keyword pipeline (gperf step) before validating, so the input isn't partial.","Add a test asserting the post-substitution output contains exactly N 'int' tokens."],"tags":["codegen","regex","assertion","keywords","v8-build"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}