thedotmack/claude-mem · error · Error
strip introduced ${afterErrs - beforeErrs} new parse error(s
Error message
strip introduced ${afterErrs - beforeErrs} new parse error(s); refusing to write What it means
Thrown by stripJsLike() as a safety guard: after removing comment ranges, it re-parses the result with the TypeScript compiler and compares parse-diagnostic counts. If stripping introduced any new parse errors, it refuses to write the file. This prevents a comment-stripping tool from silently corrupting source by, e.g., merging two tokens that a comment had separated (ASI/regex/string-edge cases).
Source
Thrown at scripts/strip-comments.ts:161
for (const r of trailing) addRange(r);
ts.forEachChild(node, visitNode);
}
function addRange(r: ts.CommentRange): void {
const key = `${r.pos}-${r.end}`;
if (seen.has(key)) return;
seen.add(key);
const text = source.slice(r.pos, r.end);
if (isDirectiveJs(text)) return;
ranges.push([r.pos, r.end]);
}
visitNode(sf);
const out = spliceRanges(source, ranges);
const after = ts.createSourceFile('check', out, ts.ScriptTarget.Latest, true, kind);
const afterErrs = parseDiagnosticsCount(after);
if (afterErrs > beforeErrs) {
throw new Error(`strip introduced ${afterErrs - beforeErrs} new parse error(s); refusing to write`);
}
return out;
}
function collapseBlankLines(s: string): string {
return s.replace(/(?:[ \t]*\n){3,}/g, '\n\n');
}
function spliceRanges(source: string, ranges: Array<[number, number]>): string {
ranges.sort((a, b) => a[0] - b[0]);
let out = source;
for (let i = ranges.length - 1; i >= 0; i--) {
const [s, e] = ranges[i];
let removeStart = s;
let removeEnd = e;
let lineStart = s;
while (lineStart > 0 && (out[lineStart - 1] === ' ' || out[lineStart - 1] === '\t')) {
lineStart--;View on GitHub (pinned to d768ba3643)
Solutions
- Add the @strip-comments-keep marker at the top of the offending file so it is skipped entirely.
- Inspect the reported file: re-parse mentally what the comment was separating and either keep that comment or add a semicolon/parenthesization so removal is safe.
- Run the script with --dry-run --verbose to identify which file fails, then exclude it via SKIP_PATHS/SKIP_BASENAMES if it is generated/vendored.
- Report a parser-edge-case bug if the file is ordinary TS with no regex/JSX tricks.
Example fix
// before — file trips the guard after stripping export const a = 1 // some comment const b = 2 // after — add the keep marker at top of file so it is skipped // @strip-comments-keep export const a = 1
Defensive patterns
Strategy: try-catch
Validate before calling
// skip files explicitly marked to keep
if (KEEP_MARKER.test(original.slice(0, 4096))) { stats.skipped++; return; } Try / catch
try {
stripped = stripJsLike(original, ext);
} catch (e) {
stats.errors.push(`${relPath}: ${(e as Error).message}`);
return; // do not write a possibly-corrupt file
} Prevention
- Run strip-comments with --dry-run --verbose first to see which files trip the guard.
- Mark generated/vendored/unusual files with @strip-comments-keep at the top to skip them.
- Never bypass the re-parse guard; it is the only thing preventing silent source corruption.
When it happens
Trigger: Removing a line comment that was acting as ASI separation between two tokens, turning them into one. Removing a block comment adjacent to a regex literal so the `/` is reinterpreted. Removing comments inside or adjacent to template literals where TypeScript' comment-range detection spanned into expression text. Edge cases in ts.getLeadingCommentRanges/getTrailingCommentRanges on JSX or decorator syntax.
Common situations: Running strip-comments across a large codebase and one unusual file (heavy regex, dense JSX, decorator metadata) trips the parser. A file where a `//` appears inside a string but was mis-detected as a comment range. New TypeScript syntax the parser handles differently after comment removal.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Hand-edited shell string detected in ${filePath} (mcp-search
- Hand-edited shell string detected in ${filePath} (${dottedPa
- Hand-edited Windows shell string detected in ${filePath} (${
- plugin/scripts/bun-runner.js is missing fixBrokenScriptPath
- plugin/scripts/bun-runner.js uses optional chaining (?.) or
AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12).
Data as JSON: /api/errors/9cdb645f13841bb4.
Report an issue: GitHub.