{"record":{"id":"6aae14aa0c6c1000","repo":"can1357/oh-my-pi","slug":"invalid-log-regex-error-instanceof-error-erro","errorCode":null,"errorMessage":"Invalid log regex: ${error instanceof Error ? error.message : String(error)}","messagePattern":"Invalid log regex: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/launch/broker.ts","lineNumber":265,"sourceCode":"\t\tlogPath: string,\n\t\tpreviousPath: string,\n\t\thead: boolean,\n\t\tlines: number,\n\t\tcursor: number,\n\t\tgrep?: string,\n\t): Promise<DaemonLogRead> {\n\t\tconst [previous, current] = await Promise.all([fileTextSlice(previousPath, head), fileTextSlice(logPath, head)]);\n\t\tconst combined = `${previous}${previous && current && !previous.endsWith(\"\\n\") ? \"\\n\" : \"\"}${current}`;\n\t\tconst terminalOutput = head\n\t\t\t? truncateHeadBytes(combined, LOG_READ_BYTES).text\n\t\t\t: truncateTailBytes(combined, LOG_READ_BYTES).text;\n\t\tlet text = sanitizeText(terminalOutput);\n\t\tif (grep) {\n\t\t\tlet pattern: RegExp;\n\t\t\ttry {\n\t\t\t\tpattern = new RegExp(grep, \"u\");\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(`Invalid log regex: ${error instanceof Error ? error.message : String(error)}`);\n\t\t\t}\n\t\t\ttext = text\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.filter(line => pattern.test(line))\n\t\t\t\t.join(\"\\n\");\n\t\t}\n\t\tconst options = { maxLines: lines, maxBytes: 256 * 1024 };\n\t\treturn {\n\t\t\ttext: head ? truncateHead(text, options).content : truncateTail(text, options).content,\n\t\t\tterminalOutput,\n\t\t\tcursor,\n\t\t};\n\t}\n\n\tasync #rotate(): Promise<void> {\n\t\tawait this.#writer.end();\n\t\tawait fs.rm(this.#previousPath, { force: true });\n\t\tawait fs.rename(this.#path, this.#previousPath);","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/launch/broker.ts#L247-L283","documentation":"The broker's readFiles log reader accepts an optional `grep` parameter compiled into a RegExp with the 'u' (unicode) flag. If `new RegExp(grep, 'u')` throws — invalid pattern syntax, or constructs illegal under the unicode flag such as unescaped lone surrogate pairs or invalid \\\\u escapes — the raw RegExp engine error is rethrown wrapped as 'Invalid log regex: <detail>' so callers know the filter string, not the log data, is at fault.","triggerScenarios":"Calling readFiles with grep set to a syntactically invalid pattern, e.g. '[' or 'a{2,1}', or a pattern only invalid with /u like '\\\\u{}' or a lone surrogate ('\\\\uD800' unpaired) that the unicode flag rejects.","commonSituations":"Users typing ad-hoc filter expressions in a UI that are forwarded verbatim to the broker; copying regexes from tools using different flavor syntax (e.g. lookbehind variants, possessive quantifiers) unsupported by the JS engine; forgetting to escape special characters like ( or *; enabling /u semantics inadvertently via this fixed flag.","solutions":["Fix the pattern syntax reported after 'Invalid log regex:' — check the exact character/position in the RegExp message","Escape metacharacters (., *, [, ], (, ), etc.) that should be literal, e.g. \\\\[' instead of '['","Test the pattern in isolation: new RegExp(pattern, 'u') in a REPL before passing it to readFiles","Drop or simplify unicode-specific constructs if the /u flag is the problem (escape lone surrogates as \\\\u{...} code points)"],"exampleFix":"// before\nawait broker.readFiles({ grep: '[' }); // Invalid log regex: Unterminated character class\n// after\nawait broker.readFiles({ grep: '\\\\[' }); // matches literal '['\n// or validate first:\ntry { new RegExp(userGrep, 'u'); } catch { userGrep = userGrep.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'); }","handlingStrategy":"validation","validationCode":"function compileLogGrep(grep: string): RegExp {\n  try { return new RegExp(grep, 'u'); } catch (e) {\n    throw new Error(`Invalid log regex: ${e instanceof Error ? e.message : String(e)}`);\n  }\n}\n// call compileLogGrep(userGrep) before invoking readFiles","typeGuard":null,"tryCatchPattern":"try {\n  await broker.readFiles({ grep: userPattern });\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Invalid log regex:')) {\n    // surface the engine detail to the user and fall back to unfiltered logs\n    return broker.readFiles({});\n  }\n  throw err;\n}","preventionTips":["Validate user-supplied filter patterns with new RegExp(p, 'u') at input time and show inline errors","Escape metacharacters when the filter is meant to be literal text (escapeRegExp helper)","Remember the /u flag is always applied: avoid lone surrogates and octal-style escapes","Unit-test patterns sourced from config or UI free-text fields"],"tags":["regex","validation","input-validation"],"backgroundTag":"invalid-regex-pattern","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}