Troubleshooting
What the reporter prints when something goes wrong, and what to do about it.
The reporter never fails your build. Everything below shows up as a warning in the CI log - check it whenever a run is missing in Squally.
No run appears
Section titled “No run appears”The key is missing. The log says “no ingest key configured, skipping
report” and nothing is sent. Set SQUALLY_INGEST_KEY - and
SQUALLY_INGEST_URL only for a Squally other than https://app.squally.dev.
See Keys.
The key is wrong - mistyped, from another project, or replaced by a new
one. Squally answers 401, the log says “Failed to start reporting to
Squally”, and nothing from the run is sent. The job stays green, so the only
signs are that line in the log and a run that never appears.
No test ran. --list, a globalSetup or webServer that fails, or a
--grep that matches nothing creates no run.
Ingest key or read key?
Section titled “Ingest key or read key?”Squally has two kinds of key, and each belongs in its own variable:
- The ingest key starts with
sqly_(notsqly_ro_). It belongs to one project - Settings › Project › Ingest key - and the reporter sends results with it. Put it inSQUALLY_INGEST_KEY. - The read key starts with
sqly_ro_. It reads every project of an organization - Organization › Read keys - for the read API and the MCP server. Put it inSQUALLY_API_KEY.
Both can be set in the same shell or job: with SQUALLY_INGEST_KEY set, the
reporter never reads SQUALLY_API_KEY. Which variable wins when several are
set is in Which key and URL the reporter
takes. The MCP server
refuses an ingest key in SQUALLY_API_KEY at start - see
MCP server. An overview of all keys:
Keys.
A read key in place of the ingest key
Section titled “A read key in place of the ingest key”- In
SQUALLY_API_KEY(the old variable name), the reporter recognises the read key and refuses it: “SQUALLY_API_KEY holds a read key; set SQUALLY_INGEST_KEY to the project’s ingest key.” Nothing is sent. - In
SQUALLY_INGEST_KEYor theapiKeyoption, the reporter refuses it too, before sending anything: “SQUALLY_INGEST_KEY holds a read key (sqly_ro_…); reporting needs the project’s ingest key (Settings › Project › Ingest key). Nothing from this run will be sent.” A reporter before 0.12.0 sends it, and Squally answers401with the coderead_api_key.
429 Too Many Requests
Section titled “429 Too Many Requests”Squally accepts up to 300 requests per minute per ingest key, and every shard
of a run uses the same key. On a 429 squally-reporter 0.17.0 and newer retry
the request for up to 90 seconds: as long as Retry-After says, otherwise
after 1, 2, 4, 8 seconds and so on, never more than 30 seconds between tries.
If it is still refused then, the batch is dropped, the run carries on, and one
line at the end of the CI log says how many results did not reach Squally -
see When Squally cannot be reached for a
while. The run
then shows that results are missing. (Up to 0.16.0: at most five tries within
about 15 seconds, and a “Failed to send N result(s) to Squally” line per
dropped batch.)
403 with x-vercel-mitigated: challenge
Section titled “403 with x-vercel-mitigated: challenge”Vercel’s firewall in front of Squally sometimes challenges one runner for a
few minutes. It answers 403 with the header x-vercel-mitigated: challenge
(or deny) - this is not about your key. squally-reporter 0.17.0 and newer
treat it like a 429 and retry; older reporters dropped the request at once,
and on the start of a run lost the whole run with “did not answer as Squally
(HTTP 403, not Squally’s JSON). A login or proxy in front of it?”. Update the
reporter.
410 Gone
Section titled “410 Gone”Reporters older than squally-reporter 0.5.0 use an ingest route that no longer
exists. Squally answers 410 with the code ingest_v1_removed and stores
nothing. Update the reporter:
npm install -D squally-reporter@latestResults are missing
Section titled “Results are missing”When fewer results arrive than the reporter produced, the run says so: “N of M results did not reach Squally.” - and, for a sharded run, which shards they belong to. The CI log of that job says how many were not delivered and why - since squally-reporter 0.17.0 in one line at the end, before that one line per dropped batch. This needs squally-reporter 0.6.0 or newer.
A job is refused at its start
Section titled “A job is refused at its start”Since squally-reporter 0.11.0, Squally refuses a job at its start when it
would share a run with another job of the same CI run. Squally answers 409;
the reporter prints one block, sends nothing more for that job, and does not
retry. Your test run and its exit code are not affected.
ci_run_collision - another job already reports under the same run ID
and shard:
[squally-reporter] Squally refused this job (ci_run_collision): another job already reports under the CI run id "12345678901-1". No results from this job will be sent to Squally. Your test run and its exit code are not affected. Give every job of the workflow its own SQUALLY_CI_JOB_KEY - the shards of one job share it. For a matrix:followed by a matrix example. Typical causes: two matrix jobs without a key,
or two jobs with the same key, running at the same time. When the job has a
key, the block says which one and that another job uses the same key or the
same SQUALLY_CI_RUN_ID.
ci_run_reused - the run ID belongs to a run that has already ended:
[squally-reporter] Squally refused this job (409): The CI run id "nightly" already belongs to run #41, which ended on 2026-10-20, so this job is not recorded - a retry that keeps the id is refused. If you set SQUALLY_CI_RUN_ID yourself, it must be different for every CI run: for example your CI's build id, plus the attempt. - no results from this job will be sent. Your test run and its exit code are not affected.Two causes:
- A fixed
SQUALLY_CI_RUN_ID. A value that is the same in every CI run, such as a constant or the commit SHA, lets only the first run in; every later one is refused. Use your CI’s build ID, plus the attempt if it re-runs builds under the same ID. See Reporter setup. - A retried job on a provider that keeps the run ID (a GitLab job retry, for example). Nothing to fix with a setting - see Sharded runs.
Squally answers this case since 27.10.2026; before, it was refused as
ci_run_collision. Every reporter from 0.11.0 on prints the sentence above.
ci_run_mixed - the run ID would put an unsharded job and a sharded one,
or shards of different totals, into one run:
[squally-reporter] Squally refused this job (ci_run_mixed): the CI run id "12345678901-1" would mix sharded and unsharded jobs, or shards of different totals, in one run.What to set for ci_run_collision and ci_run_mixed: a
SQUALLY_CI_JOB_KEY per job, shared only by the shards of that job -
${{ matrix.browser }} for a browser matrix, ${{ matrix.suite }} for
suites. See
Reporter setup. A retry
that keeps the run ID cannot be fixed with a key: the key is the same in the
retry - see Sharded runs.
A reporter older than 0.11.0 is never refused at the start; it gets the message below instead.
Squally has already completed the run
Section titled “Squally has already completed the run”[squally-reporter] Squally has already completed run … for CI run id "…" - no further results from this job will be sent.Another job used the same run ID and finished first - a matrix job, or a
re-run on a provider that keeps the run ID - and Squally refuses results for
a run that has completed. The reporter says so once and sends nothing more
for the job. Since 0.11.0 the message ends with what to set:
SQUALLY_CI_JOB_KEY, unique per job and shared only by the shards of one
job; older reporters suggested a hand-built SQUALLY_CI_RUN_ID. The job’s
exit code is not affected.
Run still running
Section titled “Run still running”A run whose job was killed before the reporter could report its end stays Running until Squally’s hourly check marks it Incomplete - see Timeouts. A cancelled GitHub Actions workflow ends this way too, unless the workflow has the step that marks it cancelled - see GitHub Actions - or someone cancels the run from its page in Squally.
More detail
Section titled “More detail”Set SQUALLY_DEBUG=1 - any non-empty value turns it on, 0 and false
included; unset it to turn it off - to print detail the reporter otherwise keeps quiet: what
it found when reading the browser console out of a trace, and why it could not
resolve the git context or the tested revision. Problems are printed without
it.