`check --write` rewrites `{@const x = y}` into invalid `{@const (x = y)}` in Svelte files (2.5.14 regression)
summary
On a Svelte file, with html.experimentalFullSupportEnabled: true and html.formatter.enabled: true,
biome check --write rewrites
{@const x = y}into
{@const (x = y)}which is not valid Svelte: Expected identifier or destructure pattern
(https://svelte.dev/e/expected_pattern). Svelte 5.56.9 and 5.57.0 both reject it.
The rewrite is silent: no rule is named, no diagnostic is emitted, and biome check (without
--write) reports nothing on a file that already contains the invalid form. One formatter run leaves
the file unparseable, so the dev server serves an error overlay and the app never boots.
Regression: 2.5.13 and 2.4.0 do not do this.
environment
@biomejs/biome2.5.14 (CLI,darwin-arm64, also reproduced withbunx @biomejs/[email protected])- macOS 15 (arm64), bun 1.x
- Svelte 5.57.0 (also rejects it on 5.56.9)
- regressed from 2.5.13 (2.5.13 and 2.4.0 both behave correctly)
config
Two keys are enough:
{
"html": {
"experimentalFullSupportEnabled": true,
"formatter": { "enabled": true }
}
}html.experimentalFullSupportEnabled: truealone does not reproduce (biome does not re-print the template).html.formatter.enabled: truewithout the experimental flag does not reproduce.- Both together: reproduces, deterministically, on every run.
reproduction
Probe.svelte:
<script>
let messages = [{ role: "user", text: "a" }];
let streamingMessageIndex = 0;
</script>
{#each messages as msg, i}
{#if msg.role === "system"}
<p>system</p>
{:else if msg.role === "tool"}
<p>tool</p>
{:else}
{@const streaming = i === streamingMessageIndex}
{@const steps = msg.text}
<p>{streaming} {steps}</p>
{/if}
{/each}biome check --write --config-path=biome.json Probe.svelteactual
{:else}
{@const (streaming = i === streamingMessageIndex)}
{@const (steps = msg.text)}
<p>{streaming} {steps}</p>
{/if}Checked 1 file. Fixed 1 file. — no rule name, no diagnostic, no unsafe-fix confirmation. The rewrite is silent.
expected
The file unchanged: it is already formatted, and {@const x = y} is the only syntax Svelte accepts here.
impact
The rewritten form does not parse:
{svelte compile} Expected identifier or destructure pattern
https://svelte.dev/e/expected_patternSo one biome check --write leaves the file syntactically invalid: the dev server serves an error overlay,
the app never boots, and any screenshot/e2e run against that checkout fails. It also survives review
easily, because biome reports nothing.
Both sides of it are silent:
- on write:
Fixed 1 file, no rule attributed, so a formatter run looks clean; - on check:
biome check Probe.svelte(no--write) reports nothing on a file that already contains the invalid{@const (x = y)}— biome accepts what biome produced.
notes from narrowing it down
| run | result |
|---|---|
check --write, 2.5.14, flag + html.formatter.enabled |
parens added (2/2 runs) |
check --write, 2.5.14, flag only |
unchanged |
check --write, 2.5.14, html.formatter.enabled only |
unchanged |
format --write, 2.5.14, same config |
unchanged (also unchanged on deliberately mis-indented input) |
lint --write, 2.5.14, same config |
unchanged |
check --write, 2.5.13 / 2.4.0, same config |
unchanged |
check --write with --formatter-enabled=false --linter-enabled=false --assist-enabled=false |
still added parens |
check --write with html.experimentalFullSupportEnabled: false |
unchanged |
check --write with html.formatter.enabled: false |
unchanged |
Two things worth flagging for whoever picks this up:
format --writeandcheck --writedisagree on the same file and config.checkre-prints the template and mangles{@const};formatre-prints it and does not. The three--*-enabled=falseflags being ignored suggests the rewrite is not a normal fix pass.- The trigger needs
html.formatter.enabled, which is why ahtml.experimentalFullSupportEnabled-only config looks innocent.
Workaround in the affected project: pin @biomejs/biome to 2.5.13, which formats Svelte files
correctly and does not rewrite {@const}.
Source: biomejs/biome