Troubleshooting
When cora stops with an error, or a cora-mcp tool returns one, start with the error’s entry in the error reference. It says what the error means and what to do about it. The docs: line under the error, and a cora-mcp error’s docsUrl, link that entry.
Scanning
Section titled “Scanning”A target was not scanned
Section titled “A target was not scanned”When no new violation fails the gate, cora scan exits with code 2, and its summary says so. It lists each target it did not scan, with why in words and the detail after it in parentheses:
Not scanned: http://localhost:4173/: the page did not load (page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:4173/)
Gate incomplete: 1 target was not scanned, so the run could not confirm a passTargets: 1 (1 not scanned)Issues: 0Duration: 2.4 sResults: .cora/runs/20261006T171204523Z-p7m2q9xd.jsonThe run still wrote its results file, which gives each target that was not scanned a coverage reason, a code with the same detail. In CI, the report directory’s summary.md lists them too. The common reasons, by the words the summary gives and their codes:
- the page did not load (
navigation-failed): the app was not running, or the page answered with an HTTP error. - the page redirected to another page (
redirected): the page sentcorato a page the run did not scan, such as a sign-in service on another host. - the scan ran out of time (
timed-out): the visit outlastedpage.timeout. Raise it, or retry the visit withpage.retries. - the page never became ready (
not-ready): the config’spage.waitForthrew, or is not valid CSS. - the page stopped answering (
page-unresponsive): usually an openalert()blocked the page.
The coverage reasons reference lists every reason. Redirects and failures says how cora scan records them. Exit code 2 also means an error stopped the command: the exit codes say how a CI script tells the two apart.
The summary says a target was scanned before it settled
Section titled “The summary says a target was scanned before it settled”cora scan scanned the page while it was still changing, so its findings may differ between runs. The summary counts it as scanned before it settled. Findings that differ between runs says what it waited on, and what to change.
Pages behind a sign-in were scanned as the sign-in page
Section titled “Pages behind a sign-in were scanned as the sign-in page”Each page redirected to the sign-in page. The results file records each as redirected, with the page it landed on. When the sign-in page is on the same host, cora scans it as a target of its own, and the gate counts each redirect as scanned there.
- Give
coraa signed-in browser, withbrowser.storageStateorbrowser.setup: see Signing in. - Make
browser.setupfail when sign-in fails, such as by waiting for the signed-in page. Asetupthat throws fails the scan withsignin.setup-failed. - A storage-state file holds session cookies, which expire. Save the file again when its session ends. A file that is missing fails with
signin.storage-state-not-found.
No token reached the CI job
Section titled “No token reached the CI job”The job fails with account.missing and exit code 2. cora found no CORA_TOKEN, and a CI runner holds no signed-in credential.
- Set a CI token as
CORA_TOKENin the CI system’s secrets, and pass it to every step that runscora scan,cora report mergeorcora baseline update. - In Azure Pipelines, a secret variable reaches a script only when the step maps it in its
env. - A pull request from a fork gets no secrets, and neither does a Dependabot run unless the secret is also one of Dependabot’s. Skip the scan there with a notice, as Your account in Running in CI shows.
The uploaded report is empty
Section titled “The uploaded report is empty”.cora/ is hidden, since its name starts with .. actions/upload-artifact skips hidden files unless its include-hidden-files is true.
cora scan writes the report directory only in CI, or where --report names one. Outside a project, it lands in .cora/report/ in the folder the job runs cora in. The report directory lists what it holds.
Account and network
Section titled “Account and network”cora cannot reach the CORA service
Section titled “cora cannot reach the CORA service”A command fails with service.unreachable. The machine may be offline, a firewall may block the connection, or a proxy may refuse it. The message says what failed, with the network error’s code, such as ECONNREFUSED, or gives the timeout it reached.
- On a network that reaches the internet only through a proxy, name it in
HTTPS_PROXY: see Proxies. - On a slow proxy or VPN, raise the request timeout.
Behind a TLS-inspecting proxy
Section titled “Behind a TLS-inspecting proxy”A proxy such as Cloudflare WARP, Zscaler or Netskope signs each HTTPS connection again with a root certificate of its own. Without that root, a request fails with service.unreachable, and its message gives the TLS error’s code, such as SELF_SIGNED_CERT_IN_CHAIN.
Ask your IT team to install the root in the operating system’s store, which cora and cora-mcp trust. Or save it as a PEM file, and name the file in NODE_EXTRA_CA_CERTS. Trusted certificates covers both, and the Node.js releases that read less of the store.
Coding agents
Section titled “Coding agents”cora-mcp logs on stderr, which the agent’s client keeps. Its tools return their errors to the agent, each with a code from the error reference. Seeing cora-mcp’s stderr shows where each client keeps it.
The browser cannot open a window
Section titled “The browser cannot open a window”Where cora-mcp finds no display, its browser runs without a window, and cora-mcp warns setting ignored as it starts, naming mcp.headless and no-display. Under Codex on Linux, a desktop’s display reaches an entry of your own only when its env_vars names DISPLAY.
Where a display is set but refuses the window, the browser fails to start with browser.launch-failed. Run it headless with --headless in the entry, CORA_MCP_HEADLESS=1, or mcp.headless in your user config: see Headed or headless.
The server times out on its first start
Section titled “The server times out on its first start”The client stopped waiting while npm downloaded cora-mcp.
- Codex waits 10 seconds by default: raise the entry’s
startup_timeout_sec. - Claude Code waits 30 seconds: raise
MCP_TIMEOUT, in milliseconds, as inMCP_TIMEOUT=60000 claude. - Or fetch the release before the agent starts.
npx cora initfetches it as it sets a coding agent up, andnpx --yes --prefer-offline=false @vispero/cora-mcp@<version> --versionputs it in npm’s cache.
When it fails on every start, not only the first, see the server fails to start when npm’s proxy or registry can’t be reached.
The server fails to start when npm’s proxy or registry can’t be reached
Section titled “The server fails to start when npm’s proxy or registry can’t be reached”npx is waiting for a connection that never opens, to npm’s registry or to the proxy that npm’s settings or HTTPS_PROXY name, such as a corporate proxy while you’re off its VPN. It waits rather than starting cora-mcp from npm’s cache, for longer than your agent’s startup timeout. Raising that timeout helps only where the network drops the connection, and then every start waits for the operating system to give up. On that network, run npm config set offline true, or remove the proxy from npm’s settings and HTTPS_PROXY and https_proxy from the agent’s environment, then restart the server:
- In Claude Code, open
/mcp, selectplugin:cora:coraand choose Reconnect. A new session skips a server that failed to connect in the last 15 minutes. - In Codex, start a new session.
Run npm config delete offline once you’re on a network that reaches the registry again, since offline applies to every npm command on the machine and fails a release npm hasn’t cached (npm’s registry).
cora-mcp warns matching release unavailable
Section titled “cora-mcp warns matching release unavailable”cora-mcp could not fetch the project’s release in time, so it serves with the release the agent started. That release’s rules and fingerprints may differ from the project’s. Run the command the warning gives, then restart the server. Version alignment says how cora-mcp picks its release.
npm fails with ENOENT under pnpm
Section titled “npm fails with ENOENT under pnpm”npm fails with ENOENT on a node/lib path when cora init or cora mcp runs it through pnpm, as cora --debug mcp shows. When pnpm manages the project’s Node.js, through devEngines.runtime, pnpm exec and pnpm cora put pnpm’s own Node.js first on the PATH, and npm cannot find its files there. Fetch the release from a shell where node is your own installation: npx --yes --prefer-offline=false @vispero/cora-mcp@<version> --version.
cora-mcp cannot write its state
Section titled “cora-mcp cannot write its state”A scan, verify_fix, summarize_fixes or a browser tool fails with mcp.state-unwritable, naming the state directory it could not create or write. cora-mcp keeps its state in .cora/ in the folder the agent’s client started it in, the folder you opened in the agent, and that folder is one it cannot write, such as a system folder. The tools that only read still work there.
- Open a project folder, or another folder you can write, in the agent.
- In Codex, set the
cwdof cora-mcp’s entry to such a folder. - Or set
CORA_STATE_DIRECTORYin the entry’s environment to a directory cora-mcp can write (The state directory).
Claude Code’s agent does not use CORA’s tools
Section titled “Claude Code’s agent does not use CORA’s tools”Check that /mcp shows the server connected. Claude Code loads the tools of a server you add on demand, through its tool search: Claude Code says how to load them as every session starts.
The project agent has no CORA tools
Section titled “The project agent has no CORA tools”The project agent, cora-a11y-fixer, says CORA’s MCP server is not connected.
- Claude Code starts the agent’s own server only in a folder you trusted.
- On its first start, npx may still be downloading cora-mcp when Claude Code stops waiting. Dispatch the agent again, or let
npx cora initfetch the release ahead of time as it sets Claude Code up. - When the agent says CORA’s plugin is not enabled, install the plugin, as In Claude Code shows: the agent’s skills come from it.
cora initenables it in the project’s settings, but each person installs it once.
The project agent describes its setup.
CORA’s hooks do nothing
Section titled “CORA’s hooks do nothing”Check each of what the hooks need. Under Codex, they also wait until you trust them, and Claude Code’s disableAllHooks turns them off.
Findings that differ between runs
Section titled “Findings that differ between runs”A finding that comes and goes between runs of the same page usually comes from a page still changing while it is scanned. Each run then reads it at a different moment.
cora scans a page once it settles, as Waiting for a page describes. When it gives up first, it scans the page as it is:
- The results file records the target as
unsettled, with the settle timeout that passed. cora scan’s summary counts it asscanned before it settled. The report directory, the GitHub Actions annotations and cora-mcp’s scan results name it too.- The
page did not settlewarning names inwaitingOnwhat settling still waited on.
What each waitingOn value means:
dom: the page’s documents kept changing, such as a ticker or a carousel that never stops.load: the page was still loading, such as a stylesheet or an image that had not arrived.frames: an iframe was still loading.fonts: a font was still loading.animations: an animation that ends, such as a slow fade, was still running, or had ended within the quiet window.requests: a request for a document, a stylesheet, a script, a font, an image or data was still in flight, or had ended within the quiet window.
Then, for the page’s route in routes:
- Raise
page.settle.timeoutfor a page that settles late. - Raise
page.settle.requestTimeoutwith it for a page that waits on a slow request. - Hold the scan until the content you mean to check is there, with
page.waitFor. - Raise
page.settle.quietWindowfor content that arrives after a pause, such as results behind a slow debounce.
Findings that differ between machines, rather than between runs, can come from each machine’s locale or time zone. Every page loads in the config’s browser.locale and browser.timezone, whatever the machine’s own: see Locale and time zone.
Reporting a problem
Section titled “Reporting a problem”Send a bug report to cora@vispero.com, with:
- what you ran, and what happened;
- the output of
npx cora info, or the JSONnpx cora info --jsonprints; - the crash file, when
coraor cora-mcp wrote one.
Logs and bug reports says what cora info prints, and What logs contain what to review in a file before you send it.