Skip to content

Fix RegexpError 500 in search highlighting when a term contains regex metacharacters - #479

Closed
jeremy wants to merge 1 commit into
mainfrom
fix-search-regexp-escape
Closed

Fix RegexpError 500 in search highlighting when a term contains regex metacharacters#479
jeremy wants to merge 1 commit into
mainfrom
fix-search-regexp-escape

Conversation

@jeremy

@jeremy jeremy commented Aug 26, 2026

Copy link
Copy Markdown
Member

Problem

SearchesHelper#whole_word_matchers interpolates a matched term straight into /\b#{term}\b/ without escaping it:

def whole_word_matchers(terms)
  terms.map { |term| /\b#{term}\b/ }
end

These terms are not the raw search query — they are spans pulled from SQLite FTS5's highlight() output, which can include document punctuation. A phrase match spanning something like foo) bar produces a term with an unbalanced parenthesis, so the Regexp constructor raises RegexpError and the leaf page 500s instead of rendering the highlighted result.

Reproduction: a book body containing alpha) omega, then viewing that page with ?search="alpha omega" (a phrase query) raises RegexpError: unmatched close parenthesis: /\balpha) omega\b/.

Fix

Escape the term with Regexp.escape before interpolation so metacharacters are matched literally:

terms.map { |term| /\b#{Regexp.escape(term)}\b/ }

The whole-word \b boundaries and the rest of the highlighting behavior are unchanged; the escaped term still highlights correctly.

Tests

  • Helper test: highlight_searched_content handles a matched term containing regex metacharacters.
  • Controller test: viewing a published book's page with a phrase search whose highlight span contains metacharacters returns success and highlights the span.

Both fail with RegexpError before the change and pass after.

… metacharacters

SearchesHelper#whole_word_matchers interpolated a term straight into
/\b#{term}\b/ without escaping it. The terms come from SQLite FTS5
highlight() spans, which can carry document punctuation — a phrase match
spanning "foo) bar" yields a term with an unbalanced parenthesis, so the
Regexp constructor raises RegexpError and the leaf page 500s.

Escape the term with Regexp.escape so metacharacters are matched
literally. Adds a helper test and a controller test covering a phrase
match whose highlight span contains metacharacters.
Copilot AI balanced review requested due to automatic review settings August 26, 2026 04:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Escapes FTS5 highlight spans before regex interpolation, preventing RegexpError while preserving literal highlighting.

Changes:

  • Applies Regexp.escape to matched terms.
  • Adds helper and integration regression coverage.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
app/helpers/searches_helper.rb Safely constructs highlight regexes.
test/helpers/searches_helper_test.rb Tests metacharacter highlighting.
test/controllers/leafables_controller_test.rb Tests the full page-rendering regression.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +37 to +39
section = Section.new(body: "alpha) omega in the body")
books(:handbook).press(section, title: "Punctuated")
section.leaf.reindex

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f12c4cf0cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +37 to +38
section = Section.new(body: "alpha) omega in the body")
books(:handbook).press(section, title: "Punctuated")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reuse the existing section fixture

This test creates and presses a new Section even though leaves(:welcome_section) already provides a section-backed leaf. Update that fixture's body for the test and reindex it instead, avoiding unnecessary record creation and following the repository's explicit testing convention.

AGENTS.md reference: AGENTS.md:L5-L6

Useful? React with 👍 / 👎.

@jeremy

jeremy commented Aug 26, 2026

Copy link
Copy Markdown
Member Author

🤖 Superseded by #481, which was merged and folded in this exact Regexp.escape fix (now on main at app/helpers/searches_helper.rb). Closing as redundant — the RegexpError 500 is fixed.

@jeremy jeremy closed this Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants