Skip to content

Report token and location for common template syntax errors - #680

Merged
stencil-harness[bot] merged 1 commit into
masterfrom
robot/issue-314
Nov 8, 2026
Merged

stencil-harness[bot] merged 1 commit into
masterfrom
robot/issue-314

Conversation

@stencil-harness

Copy link
Copy Markdown
Contributor

Refs #314

Improves compile-time error messages for several malformed-template cases from #314. Exception types stay the same, and existing message text is kept as a prefix, so callers matching on type or message prefix keep working.

Template Before After
{{#if !File}} {{/if}} An unhandled exception occurred while trying to compile the template → inner ArgumentException: must be reducible node Unexpected '!File' inside an expression: '!' can only start a comment (e.g. '{{! comment }}') and is not a negation operator. Use '#unless' to negate a condition + Occured at: 0:6
{{#each items}}test (never closed) Reached end of template before block expression '#each' was closed same + location of the opening {{#each}}
{{#if 0}}test{{/unless}} A closing element '/unless' was found without a matching open element same + location of the stray {{/unless}}
{{File}}} Starting and ending handlebars do not match + location same + : expression opened with '{{' was closed with '}}}'

How

  • Source locations were already recorded on lexer tokens, but they were lost when helper arguments were accumulated (HelperArgumentAccumulator rebuilt HelperExpression without its context) and when words became PathExpressions. Both now keep the location, which also gives location info to other existing errors that already passed helperExpression.Context (e.g. #if requires exactly one argument).
  • CommentToken/LayoutToken now record where they start. CommentAndLayoutConverter rejects a ! comment that doesn't come straight after the opening braces. Every such template already failed to compile (verified for block helpers, simple helpers, #if/#unless/#each/#with, else if, hash arguments, partials and sub-expressions), so the only change is a clearer error. Normal comments ({{! x }}, {{ ! x }}, {{!-- ... --}}, {{~! x ~}}) and layouts ({{!< layout}}) behave as before.

Not changed

  • An unclosed {{#File}}, where File isn't a registered block helper and no {{/File}} follows, still compiles and renders File's value. Handlebars.js rejects this, but making it throw would break existing templates, so that decision is left to a maintainer.
  • Locations still use the existing line:column format with 0-based line numbers.

Tests

New cases in ExceptionTests cover each message and its reported location, and check that comments still compile. The full suite passes (2224 tests).

🤖 Generated with Claude Code

Closes #314

- Using '!' as an argument (e.g. {{#if !value}}) now throws a
  HandlebarsCompilerException naming the offending token and its location
  and pointing to #unless, instead of an internal "must be reducible node"
  error wrapped twice.
- "Reached end of template before block expression ... was closed" now
  reports the location of the unclosed opening tag.
- "A closing element ... was found without a matching open element" now
  reports the location of the stray closing tag.
- "Starting and ending handlebars do not match" now says which braces
  were used to open and close the expression.

Source locations were already tracked on tokens but were dropped when
helper arguments were accumulated and when words became path
expressions; they are now carried through. Exception types are
unchanged, and existing message text is kept as a prefix.

Refs #314

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Nov 8, 2026

Copy link
Copy Markdown

@stencil-harness
stencil-harness Bot merged commit 47960fa into master Nov 8, 2026
7 checks passed
@stencil-harness
stencil-harness Bot deleted the robot/issue-314 branch November 8, 2026 23:40
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.

Please report betters errors (context) when having mistakes in the template

0 participants