Troubleshooting
On this page
Start here:
zest doctor page.html
It checks Node, the file, the notes folder, git, your browser, your keys and the network, and prints one fix for anything that is not right. In the editor, the dot on More is green when all is well; More > Setup shows the same table.
In Claude Code
| You see | Cause | Fix |
|---|---|---|
zest: command not found | In Claude Code: the plugin's bin/ is not on this session's PATH (Claude Code was not restarted). In your own terminal: the plugin puts zest on Claude Code's PATH only | In Claude Code, restart it; the skills fall back to node "${CLAUDE_PLUGIN_ROOT}/bin/zest" on their own. In your terminal, run the command as Zest wrote it in the editor or zest doctor (node "<plugin>/bin/zest" …), or make zest work everywhere once: node "<plugin>/bin/zest" link (see Command line). |
| 🛑 None of ~/.local/bin, /opt/homebrew/bin, /usr/local/bin is on your PATH and writable | zest link found no usual folder it can put the link in | mkdir -p ~/.local/bin, add it to your PATH in ~/.zshrc or ~/.bashrc (export PATH="$HOME/.local/bin:$PATH"), open a new terminal and run zest link again. Or name a folder on your PATH: zest link <folder> |
| 🛑 …/zest is already there and is not this Zest | Another program called zest sits in that folder | Keep it and link into another folder (zest link <folder>), or replace it: zest link --force |
| 🛑 … is not a folder you can write to | The folder named to zest link is missing or not yours | Name a folder on your PATH that you own |
zest in your terminal runs another copy of Zest | A zest link made before a plugin update still points at the old copy (zest doctor says so on its Terminal row) | Run zest link again from Claude Code |
| 🛑 Zest needs Node 18 or newer | An old Node | Install the current LTS from nodejs.org |
| 🛑 … is not an .html file | You named a Markdown or other file | Ask your agent to render it to HTML first |
| 🛑 The editor server did not start | Something in the log it prints | zest serve --root <folder> shows the error in the foreground |
| Could not open a browser here | A remote or headless machine | Open the printed address yourself |
| Rounds run on Claude Opus, which needs Claude Code logged in | Your team's extension routes this round to one of Claude's own models, and Claude Code has no login here | claude auth login, or copy the prompt instead |
| … changed since you approved it, so its notes store is off. Nothing was written | Your team's extension changed (an update, or an edit), so zest notes refuses to write notes beside the page where your team would not see them | zest trust <file>, then run it again |
| No note … here: … changed since you approved it | Your team's extension changed (an update, or an edit), so its notes store is off until you approve it again | zest trust <file>, then answer again |
| Your mark was not saved | The Zest server is older than the editor | Run /artifact-editor:edit again to restart it |
| A task's change collided with another's and ran again | Two notes changed the same lines at once | Nothing to fix: Zest ran it again in the checkout. The trace says which file. |
<lane> is not available here …, so your own Claude runs it | That lane's key is not set on this machine | Set the key it names, or leave it: your own Claude does the work |
| Evals need the page in a git checkout | zest eval replays from git snapshots | Run evals on a page inside a git repo |
| No rounds remembered for this page yet | zest grooves before any round finished through Submit on this page | Nothing to fix. The first round records one. |
In the editor
| You see | Cause | Fix |
|---|---|---|
| Saved as a note for your agent: this text is not written in the file as you see it | A script builds the text | Nothing to fix. Your agent applies it on the next run. |
| That text appears N times in the file | The same words in several places | Change all of them, or leave a note for just this one |
| Live shows a blank page | The app is not running, or it refuses to be shown inside another page | Start the app, or press Open in a tab |
| These words come from a shared part, with a button for each place | On a live page, the words come from a part many pages share, and your team's extension asks where the change goes | Press the place you mean. Put it back leaves the page as it was. |
| This edit changed formatting | You deleted a link or typed across bold or italic text | Your agent applies it. To avoid this, edit one run of text at a time. |
| The file changed on disk since this tab loaded it | Your agent (or another editor) saved the file | Reload. The change you were making became a note, so it is not lost. |
| Your agent is changing the page. It reloads when the run finishes. | A run is in progress | Wait, or keep leaving notes; they wait for the next run |
| Zest's server stopped | The server was stopped, or stopped itself after two idle hours | Run /artifact-editor:edit again. Everything saved is safe. |
| This request did not come from the Zest editor | The tab is older than the server (the server restarted) | Reload the page |
| The notes file … is damaged | .zest/<page>.json stopped parsing (a bad merge, a hand edit) | Your notes are still in it. Repair the JSON, or run zest notes repair page.html to keep a copy and start fresh. Zest saves no new notes until then. |
| This page is not saved as UTF-8 | An older file in Latin-1 or Windows-1252 | Zest opens it read-only, because a save would damage every accented letter. Convert it once: iconv -f windows-1252 -t utf-8 page.html > page-utf8.html, then open the new file. Notes still work. |
| … is read-only on disk / Zest cannot write … permission denied | The file or its folder is not writable | chmod u+w page.html, or copy the page somewhere you can write to |
| The page changed while Zest was copying images | You or your agent saved during Localize | Nothing was written. The images are already in assets/; run Localize again. |
| Part of the editor did not load | A browser extension blocked a script, or the server stopped mid-load | Reload. If it repeats, try a private window, then zest doctor. |
| Nothing happens on E or N | The focus is in one of the page's own fields, or the page captures keys | Click an empty part of the page, or use the toolbar buttons |
| The editor does not appear | The page sets a Content-Security-Policy header Zest cannot remove, or the tab is not served by Zest | Open the address zest open printed, not the file directly |
Editing in place
| You see | Cause | Fix |
|---|---|---|
| No Edit here on the button, only Edit | Your dev server does not forward /__zest to the Zest service, or the service is not running | Add the forwarding for your dev server (Editing in place) and restart it; zest service status |
| No Edit here right after you updated Zest | The service still runs the release before this one | zest service stop, then zest service start (at login it starts the new one by itself) |
| Zest got a request addressed to localhost:5173, not to itself | Your dev server forwards /__zest but keeps your app's own Host header | In Vite, set changeOrigin: true on the /__zest proxy; elsewhere, set the Host to 127.0.0.1:4470 |
| This browser is not set up for Zest Edit | The browser has no zest_edit cookie | Open http://127.0.0.1:4470/__zest/hello once (or zest service hello), then reload the page |
| Zest cannot tell which file is behind this page | No registered repo maps this address | Add it to a sites entry in the repo's zest.json (or let your team's extension resolve it), then zest service add path/to/repo |
| Your team's extension in … has not been approved on this machine | The page is in a worktree whose extension you have not approved yet: an approval covers exact files in one folder | zest trust path/to/that/worktree, then press Edit here again |
zest service repos shows 🛑 gone or 🟠covered by | A worktree you registered was deleted, or you registered two checkouts of one repo (one now covers both) | zest service prune |
| Zest edits pages served on this machine only | The page is not on localhost, 127.0.0.1 or [::1] | Open it from your dev server on this machine |
| Zest gives an editing session only to the page that asks for it | The request's Origin, Referer or forwarded host named another page, or a proxy dropped the Origin header | Press Edit here on the page itself; if your own proxy rewrites headers, let it keep Origin and Referer |
| This editing session ended | The service restarted, or the tab sat unused for two hours | The editor asks for a new session by itself; if it says this, reload the page |
| This tab may only change the page it opened | A session is bound to one page | Open the other page with its own Zest Edit button |
| This address is from an earlier run of the Zest service | The service restarted since the page was opened | Open it again: zest open page.html, or its Zest Edit button |
| The Zest service is not answering / The Zest service stopped | The service is not running | zest service start (or zest service install to start it at login). Everything saved is safe. |
| The bar and toasts are gone while your app shows an error screen | Zest steps aside while a dev overlay covers the whole page (Vite's or Next.js's error screen) | Fix the error or close the overlay; the bar comes back by itself |
| The bar covers your page's own control at the bottom | Zest does not know the control floats there | Add data-zest-avoid to it; the bar and toasts lift above it |
| Saved as a note for your agent: the page redrew this part while you were typing | Your app replaced the part you were editing (a hot reload, a re-render) | Nothing to fix: your words are in a note for your agent, pinned where they were |
| The note is saved without its freeze frame | No Chrome on this machine, the page is too big to copy, or Chrome could not draw it in time | Install Chrome or set CHROME_PATH; the note and its state are saved either way |
| A freeze frame is drawn only at the address of the page you are editing | The note's address was not the page's own (a page moved between taking the note and saving it) | Leave the note again from the page |
| A new note's freeze frame, an answer or the Changes count shows only after a reload | Your dev server compresses what it forwards and holds the live events until the stream ends. Zest asks it not to (Cache-Control: no-transform); a proxy that ignores that header keeps them | Turn compression off for /__zest in that proxy. next dev and Vite need nothing |
| The editor goes away when you follow a link in your app | Zest reloads the page to open the new page's file; on a page no repo maps, it stays off | Map the page, or press Edit here on a page that is mapped |
Submit
| You see | Cause | Fix |
|---|---|---|
| Submit is not set up yet / Turn on Submit | Nobody gave Submit its yes on this machine | Click Turn on Submit for the checklist; the last step is pasting /artifact-editor:setup into Claude Code |
| Submit runs on …, but KEY is not set on this machine | A worker names a key variable that is not set | Set it in your environment or a .env beside the page, or zest runner worker off |
| … changed since you approved it, so Submit waits | A file of your team's extension changed (a pull, an edit), so its approval no longer matches | Read what changed, then zest trust page.html. A round without the extension would miss your team's notes store and setup. |
| Say what this section should do for the reader | A new section needs its job before it can be added | Write one sentence: what the reader should think or do after it |
| The block this sits next to is gone | The page changed under a placeholder | Remove the placeholder and insert it again where it belongs |
| Claude Code is not installed where Zest can find it | claude is not on the PATH the editor's server sees | Install Claude Code, or set ZEST_CLAUDE_PATH |
| Claude Code did not start: … | The file Zest found cannot be started directly (on Windows, a .cmd that is not npm's own wrapper) | Point ZEST_CLAUDE_PATH at claude.exe, or at the cli.js the wrapper starts |
| Claude Code … is too old to run notes unattended | An older Claude Code | claude update |
| Claude Code is not logged in | Logged out, or a new machine | claude auth login |
| Submit is turned off on this machine | ZEST_RUNNER=off | Unset it, or copy the prompt |
| Your agent asked for something Run does not allow | A note needed the web, an MCP tool, or a file outside the page's folder | Copy the prompt and run it in Claude Code, where you can approve it |
| The run stopped: it reached the spend cap / turn cap | A big round, or a note bigger than it read. Zest already tried a stopped stated-change task once more on the stronger model | Raise it: zest runner setup --budget 5, or split the notes |
| Your agent stopped without finishing the round | The run ended before answering | Read the run's log in .zest/runs/, then run again or copy the prompt |
Your agent says a picture on your note is not on disk, or (could not fetch: …) beside it | Your team keeps notes in a shared store, and the picture did not come down beside the page (.zest/notes-media/) before the round. Zest before this release never fetched it for Submit | Update Zest. For a could not fetch, check the team's store answers (zest doctor), then submit again |
When someone is already working here
| You see | Cause | Fix |
|---|---|---|
| … is working here, with Send, Run here anyway and Wait | Your team's extension says an agent did something in this page's checkout in the last 15 minutes | Pick one. Send hands your notes to that agent; Run here anyway is the old Submit. What each does |
| Nobody is working in this checkout now, so there is no agent to send these to | The agent stopped, or your team's extension stopped naming it, between the question and your Send | Press Submit again: with nobody there, it runs the round itself |
| Submit has no "…" | An older tab, or a script, asked Submit for something it does not do | Reload the page and press Submit again |
| Notes stay With … and nothing happens | The agent has not looked at its mailbox, or is gone | Changes says whether it has read them. Take them back there and Submit again, or ask that agent to run zest inbox <id> --take |
| Waiting on the bar for a long time | The agent you are waiting for keeps working, so it never goes quiet for 15 minutes | Click Waiting, then Run here now, or send the notes to it instead |
| The round that waited did not start: … | The wait ended, but the round could not start (the reason follows: a round already open, an extension waiting for your yes) | Fix what it names, then press Submit |
| Zest could not get the lock on its waiting list for 3 seconds | Another Zest stopped while it held ~/.zest/waiting.json.lock | If no Zest is running, delete the lock folder it names and try again |
That owner id is empty once it is made safe for a file name (from zest inbox) | The id has no letters or digits, so it cannot name a mailbox file | Use the id your team's extension gave, for example from zest inbox --all |
… is not yours any more: taken back by the person (from zest inbox --take) | The person took that note back, or someone answered it, after it was sent | Leave it. Answer only the notes listed with an answer: line |
| Sent notes do not show With … on the page | Your team's notes store does not keep the routed field | Nothing is lost: the agent still gets them from its mailbox. Ask whoever keeps the store to keep routed |
The ledger
| You see | Cause | Fix |
|---|---|---|
| zest ledger: … could not write a row | Zest could not write ~/.zest/ledger.jsonl (a full disk, a folder you cannot write) | Free space, or point ZEST_HOME at a folder you can write. Rounds carry on either way |
| zest ledger: …'s ledger hook failed | Your team's extension threw or did not answer in 10 seconds when handed a row | The row is in your own ledger; tell whoever keeps the extension. Rounds carry on |
… is not in a git checkout (from zest ledger sweep) | The sweep reads git history | Name the repo: zest ledger sweep path/to/repo |
| The ledger is off | ZEST_LEDGER=0 | Unset it to record again |
zest ledger sweep says nothing merged that you merged | It reads origin/main as your clone last fetched it | git fetch, then sweep again |
| …whose snapshots git no longer has | zest gc dropped the round's snapshots (after 30 days) | Nothing to do: those answers stay unsettled |
Your team's setup
| You see | Cause | Fix |
|---|---|---|
| Approve its build / a check or extension waiting for your approval | The repo's zest.json asks to run something you have not approved | Read the list, then zest trust page.html |
| Saved to page.src.html. The page itself rebuilds once its build … is approved | A built page whose build is not approved yet | zest trust page.html |
| … but its build failed | The build command errored | Run it yourself in that folder to see the whole error |
| … is not valid JSON, so Zest ignores it | A broken zest.json | Fix the JSON |
| … did not load (an extension) | An error in the extension's code | Fix it; the editor carries on without it |
| Not saved: … (a word) | Your team's zest.json blocks that word | Change the words |
| This image is locked | Your team protects it (a logo or mark) | Leave a note if it should change |
| Zest could not reach … for this page's notes | A shared notes store is down or you are offline | Notes still show once it answers; nothing was lost |
Slides (decks)
| You see | Cause | Fix |
|---|---|---|
| The slide list in this tab is out of date | The deck changed since this tab loaded it | Reload, then move the slide again |
| Two slides share the data-sid "…" | A copy pasted by hand kept its data-sid | Give one a new data-sid in the source, then reload |
A slide has no </section> | A slide's section is not closed in the source | Close it; until then Zest moves no slides |
| There is no slide "…" in the deck now | Someone removed or renamed it | Reload |
| This is the only slide | Remove would leave an empty deck | Add a slide first |
| The saved views in this deck are not valid JSON | The zest-deck-views script near the end of the page was edited by hand | Repair the JSON, or delete that script to start fresh. Zest will not overwrite it. |
| This page is older than its source: its build has not run | The source changed and the page was not rebuilt yet | Reload; Zest runs the build before it serves the page |
| This slide is hidden in this run-through | The deck skips hidden slides, so it cannot show one | Press Show beside it |
| Zest could not take thumbnails: No Chrome, Chromium, Edge or Brave found | No Chromium-family browser | Install Chrome or set CHROME_PATH. Everything else in Slides works without it. |
| … did not work: the deck did not show it (thumbnails) | The deck's own script did not move to that slide by its #n.k address or DeckGo | Nothing breaks; that card shows its title instead |
| Zest is already taking thumbnails | A second request while the first runs | Wait for it; it takes about half a second a slide |
Levers
| You see | Cause | Fix |
|---|---|---|
| The levers block is not valid JSON | The zest-levers script was edited by hand and has a typo | Fix the JSON inside <script id="zest-levers">, then reload |
| The levers block has no "schema" list | The block is missing "schema": [ ... ] | Add one object per lever |
| Lever … needs … (a toast when the tab opens) | A lever in the schema is missing a field or has a wrong one | Fix that lever in the block; the message names the field |
| This tab did not say which version of the page it has | The tab is older than the page | Reload and save again |
| A lever moves but nothing on the page changes | The lever has no css, or the page does not use that custom property | Add "css": "--name" and use var(--name) in the page's styles, or listen for zest:levers |
Releases
| You see | Cause | Fix |
|---|---|---|
| A dot on the Z in the toolbar, or "Artifact Editor … is out" when Claude Code starts | A newer release is published | claude plugin marketplace update zest, then claude plugin update artifact-editor@zest, then restart Claude Code |
| Zest could not check for a newer release on About Zest | Offline, GitHub did not answer, or the repo has no release yet | Nothing to fix; it asks again tomorrow. zest update --now asks now |
| The check for a newer release is off | ZEST_UPDATE_CHECK=0, or your organization's policy file | Ask whoever manages the policy file, or unset the variable |
| Still the old version after updating | Claude Code loads plugins at start, and an open editor tab keeps the server it started with | Restart Claude Code, then open the page again |
The Zest Edit button
| You see | Cause | Fix |
|---|---|---|
| No button on a page | The page does not carry it, or this browser is not marked | zest service hello, or use the bookmark it offers |
| This browser is not set up for Zest Edit | No cookie in this browser | zest service hello |
| Zest cannot tell which file is behind that page | No registered repo maps that address | Add a sites entry to its zest.json and zest service add path/to/repo |
| 🟠Zest Edit: the button service is set to start at login but is not running | It stopped, or Zest moved | zest service install |
Generate
| You see | Cause | Fix |
|---|---|---|
| No OpenAI / Google key found | No key in the environment, .env or config | Paste one in the Generate tab, or set it (Configuration) |
| Zest's config file … is not valid JSON | ~/.config/zest/config.json was edited by hand and broke | Zest will not overwrite it, because your other keys are in it. Repair it, or delete it and paste your keys again. |
| OpenAI rejected the key (401) | A typo, quotes or spaces, or a revoked key | Copy the key again from platform.openai.com/api-keys |
| OpenAI says your organization must be verified | OpenAI's rule for image models | Verify at platform.openai.com/settings/organization/general (about 15 minutes), or use Google |
| OpenAI says this key is out of credit | Billing | Add credit at platform.openai.com/settings/organization/billing |
| Google says this key is over its quota | Image models need billing on the key's project | Turn on billing in Google AI Studio |
| … safety system refused this prompt | The provider's filter | Reword. Real people, brands and logos are the usual cause. |
| Google answered with words instead of an image | The prompt read as a question | Describe the picture rather than ask about it |
… could not use <model> | The model is not available to your account | Zest already tried the others. Pin one you have with ZEST_OPENAI_IMAGE_MODEL / ZEST_GOOGLE_IMAGE_MODEL. |
| … took longer than 240 seconds | A slow provider, many variants | Fewer variants, or draft quality |
Images
| You see | Cause | Fix |
|---|---|---|
| The library is offline | No connection to the CDN | Zest shows the cached or bundled list; search, generation and your own files still work |
| Openverse limits searches without an account | Too many searches from this machine | Wait a few minutes, or use the library |
| The image is over 25 MB | A huge original | Download it, shrink it, and use Upload |
| That address is not an image | A web page, not an image file | Right-click the image and copy the image address |
| That SVG carries scripts | An SVG with JavaScript or event handlers | Use a PNG, or a clean SVG |
| Zest does not fetch from private or local network addresses | The address is, or resolves to, your own machine or network | Download the file yourself and use Upload |
| Gave up after … seconds | A host that answers slowly or stalls | Try again, or download it yourself and use Upload |
Screenshots (zest shoot)
| You see | Cause | Fix |
|---|---|---|
| No Chrome, Chromium, Edge or Brave found | No Chromium-family browser | Install Chrome, or set CHROME_PATH |
| viewport only on this Node | Node older than 22 | Upgrade Node for full-page and element shots |
| Nothing on the page matches … | The note's element moved or was deleted | Shoot the full page instead |
Still stuck? Open an issue at github.com/Fresh-Context/zest with the output of zest doctor page.html.