Troubleshooting
Every finding, explained.
Each vage check finding has a rule name, the page, and the file to fix. Errors stop the build from deploying; warnings don't.
Page and build problems
| Rule |
What it means |
How to fix it |
page-error |
A page couldn't be built: invalid frontmatter, a field its layout doesn't allow, or a layout that crashed |
Read the message: it names the field or the layout error. The rest of the site is still checked. |
frontmatter-empty |
A frontmatter value came out empty |
Usually a comma or colon inside { }. Wrap the text in quotes: { q: "Is it free, really?" } |
config |
A setting needs attention, such as site still being https://example.com |
Set your real domain in vage.config.ts |
Links and files
| Rule |
What it means |
How to fix it |
link-broken |
A link points to a page or file that doesn't exist, or to a draft |
Fix the address, publish the draft, or add a redirect |
link-trailing-slash |
A link would redirect, e.g. /about |
Use /about/ |
asset-missing |
An image, script or stylesheet isn't in the build |
Put the file in public/ with that path |
redirect-target |
A redirect points to a page that doesn't exist |
Fix the target in redirects |
unsafe-url |
A link, image or form uses a script URL (javascript:), which runs code on your site |
Use a normal https: or /path/ address |
Search and sharing
| Rule |
What it means |
How to fix it |
title |
A page has no title, or more than one |
Every page needs one title in frontmatter, and the layout must write one <title> |
meta-description |
No description for search results |
Add description to the frontmatter |
canonical |
More than one canonical link, a relative one, one pointing to an unpublished page, or (warning) one pointing to another site |
Set site in the config and check any canonical: in frontmatter. A canonical to another website hands that page's ranking to it. |
jsonld |
Structured data is invalid |
Fix the JSON-LD your layout writes |
jsonld-article |
Article data is missing fields Google recommends |
Add author and datePublished, but only real values |
robots-blocks-all |
robots.txt blocks every crawler while pages are meant to be indexed |
Check seo.robots in your config |
Accessibility
| Rule |
What it means |
How to fix it |
html-lang |
The page doesn't declare its language |
Set lang in the config and write <html lang> in the layout |
img-alt |
An image has no alt text |
Describe the image:  |
img-dimensions |
An image has no width and height |
Images in public/ get them automatically; add them to images written in layouts |
link-text |
A link has no text a screen reader can announce |
Add link text or an aria-label |
Spam protection
| Rule |
What it means |
How to fix it |
link-unapproved |
A link goes to a website that isn't in links.lock.json |
If you added it on purpose: npx vage links approve <domain>. If you didn't, remove it and check the page's history. |
links-lock-missing |
There's no links.lock.json (an error when outboundLinks is "require") |
Review npx vage links, then npx vage links approve --all, or restore the file from git |
link-hidden |
A link is hidden from visitors but visible to search engines |
Remove it, or make it visible. Hidden external links are a classic sign of a hack. |
spam-pattern |
The page contains words common in injected spam |
If you didn't write them, check the page's history |
Analytics and security headers
| Rule |
What it means |
How to fix it |
analytics-event |
An element uses an event or parameter not declared in the config |
Declare it under the analytics integration's events |
analytics-duplicate |
Google's tag loads more than once |
Remove the tag from your layout, or the integration from the config |
csp-inline-handler |
An onclick="…"-style handler, which the security policy blocks |
Use addEventListener in a script file |
Common errors outside checks
- "Port … is already in use": you chose a port with
--port that another program is using. Stop that program, or pick another port. Without --port, the dev server finds a free port by itself.
- "Confirmation required": a deploy or
links approve ran without a terminal. Review with --dry-run, then re-run with --yes.
- A deploy refuses because of
wrangler.jsonc: the file names a different Worker, or doesn't serve dist/. Make the names match and set assets.directory to "dist".
- HTTP 431 in the browser on localhost: your browser sends too many cookies to
localhost. Use http://127.0.0.1:<port>/ instead.