Skip to main content
Every diagnostic carries a code, a message, a file, a line, a column and a severity:
The compiler declares 21 codes and emits 13 of them. The other 8 exist for host integrations that layer their own checks on top; the compiler never produces them.

When each code can fire

slurp validate parses and runs the compile-time security checks. slurp build does that AND renders. Four codes are render-time only, which is why a file can validate clean and then fail to build:

Codes the compiler emits

UnexpectedToken

The default parse and lex failure. Also what a construct that LOOKS like a block tag gets when no parser supports it.
Fix. Check the tag exists. The usable block tags are if, each, match, fetch, repeat, try, slot, layout, head, sections and blocks. {error} and {loading} are branch markers, legal only inside {fetch} or {try}. {with} does not exist in any form; write the full path instead. The same code covers {case} inside {match}, every operator the language does not have (===, ??, ?., in, **, typeof, the bitwise set), and a stray { in ordinary text, which the lexer reads as the start of an interpolation.

UnclosedBlock

A block tag was opened and never closed, or an expression was left open.
Fix. Remove the {/empty}. Which tags need a close and which do not:

InvalidFrontmatter

A malformed frontmatter directive or schema declaration. This is by far the largest family: a bad setting kind, a select default outside its own options, a duplicate setting key or block type, a section with no name, a max below 1, an empty @theme(), or any @target other than @theme.
Fix. Read the message; it names the exact key or token. Two rules catch most of it: every setting kind must be one of text, richtext, color, image, icon, link, select, number or toggle, and a select default must appear in its own option list.
Unknown frontmatter STATEMENTS are silently skipped, not reported. This code fires only on a malformed KNOWN one. A misspelled directive produces no diagnostic at all.

SecretEnvInTemplate

A template read env.SLURP_SECRET_something, in dotted or subscript form. Also fires for env[key] with a key that is not a compile-time constant, because such a key could resolve to a secret name.
Fix. A secret must never reach a template, because the template output is sent to the browser. Read it on the server and pass only the derived, non-secret value through the render context:

MiddlewareScopeViolation

Either request.* was used in a file that is not compiled as middleware, or a file that IS middleware read a path root other than request, env or loop.
Fix. request.* is middleware-only. In an ordinary page, take what you need from the request on the server and pass it through the render context:
Middleware is a compile OPTION, not a filename convention, so the CLI treats every file as non-middleware unless told otherwise with --middleware <DIR>. A correct middleware file reports this error until you pass that flag.

RedirectOutsideMiddleware

A {redirect} or {next} appeared in a file that is not compiled as middleware.
Fix. Both are middleware-only signals. Move the check into a middleware file, or perform the redirect on the server before rendering, and let the page assume it is reachable.

UnsafeScriptInterpolation

Two distinct rules share this code, plus two development-mode advisories. Rule 1: an expression in a <script> body with neither | js nor | json.
Fix. End the expression with | json for a bare value, or | js when it sits inside a string literal you wrote:
| unsafe_js does NOT satisfy the rule. The raw hatch in a script body is {html expr}. Rule 2: a | js slot in a JavaScript-evaluated attribute that lands in statement or expression position rather than inside a quoted string.
Fix. Quote the slot, or switch to | json:
An UNDECLARED slot in the same position is not an error: it is auto-encoded as a JSON literal, and development mode records an advisory suggesting you declare it.
HTML entity escaping does not protect a script context. A raw-text element reaches the JavaScript engine without character references being decoded, so the ordinary text escaping is inert there.Note also that a JavaScript template literal cannot be written in a <script> body at all, because Slurp claims the ${ sequence itself. Build the string by concatenation.
The two development-mode advisories under this code are the CSS-structural characters stripped from a style value slot, and an undeclared slot in a JavaScript-evaluated attribute. Both are silent in a production render, which is what slurp build always uses.

JsTemplateLiteralInAttribute

Severity: warning. A quoted HTML attribute value contains a JavaScript template literal whose ${ } slot Slurp will interpolate itself, against the SERVER render context rather than the browser one.
Fix. If the value is client-side, build the string by concatenation. If it is server-side data, drop the backticks and let Slurp interpolate.
For a client-side variable the slot renders EMPTY, with no runtime error and no other sign, so the result is a page that looks built and has dead links and unstyled elements scattered through it.For SERVER-side data it fails differently: the slot interpolates correctly, but the backticks themselves are emitted into the HTML, so the attribute value keeps a stray backtick at each end. The warning fires on ANY attribute, not only a JS-evaluated one.

UnknownFilter

A filter name that is in neither table. The value table and the loop table are disjoint, so using one where the other belongs also lands here.
Fix. Value filters, usable in ${ }: upper, lower, currency, truncate, fixed, date, default, plural, int, float, js, json, unsafe_js. Loop filters, usable ONLY in an {each} header: limit, sort, reverse, filter. See Filters. This is a RENDER-time error, so slurp validate will not report it. The renderer passes the value through unfiltered alongside the diagnostic, so the render itself completes, but the CLI treats the diagnostic as an error and emits no file.

InvalidFilterArgs

A required filter argument was missing, or could not be read as a literal. In practice this is limit() and filter().
A missing argument reports Filter 'limit' requires at least 1 argument(s) instead. Fix. Supply the argument as a literal:
Filter arguments are read as literals throughout, so a variable is seen as the empty string. default is the only exception.

MissingImageSrc

An <Image> was written with no src prop.
Fix. Give it a src:
There is no missing-dimension case. width defaults to 800 and height to 600, and both accept a literal such as width={400} as well as a context value. height is only used for the <img> attribute and is never sent to the image service.

IterationLimitExceeded

A budget was exhausted. Severity is mixed: two of the budgets are errors and the rest are warnings.
Fix. Page or pre-slice the data on the server.
A budget TRUNCATES; it never aborts the render. A 1500-item loop emits 1000 items, warns, and exits 0. On the CLI the diagnostic exists either way but is only printed with -v, so a build that quietly drops a list tail reports itself clean.A script that only checks the exit status will not catch this. Look for the warning, or count what you expected to render.

CircularImport

Two templates import each other, directly or through a chain, or the chain exceeds 128 links. Fix. Break the cycle by extracting the shared part into a third file that neither of the two imports back.
Only reachable through the virtual-files compile path used by an embedding host. Neither slurp build nor slurp validate detects it, because neither builds a cross-file import graph.

Codes declared but never emitted

These 8 are in the ErrorCode enum for host integrations to reuse. The compiler never produces them, and the note for each says what happens instead, because in several cases the condition IS detected and handled another way.

Conditions that produce no error at all

Slurp is total and tolerant. These are the failures with no diagnostic anywhere. Several of these are caught by the linter in the MCP server even though the compiler says nothing. Build with --verbose while developing, and read Common mistakes, which collects the silent failures with the fix for each.

Diagnostic limits

At most 1000 diagnostics are collected per compile. Beyond that, further ones are dropped silently, so a file with thousands of errors reports the first thousand.