ScreenshotNeo

BlogHow-to

How to Fix Chromatic CI Failures in GitHub Actions

Trace Chromatic failures to the build, token, Git context, visual checks, or PR status—and fix the failing layer in GitHub Actions.

By the ScreenshotNeo team4 October 202611 min read

To fix a Chromatic failure in GitHub Actions, start with the first relevant error in the failed job and identify which step produced it: dependency installation, Storybook production build, story extraction, Chromatic upload or verification, Git metadata detection, or pull request status reporting. Then fix that layer and rerun the workflow. A Storybook that works in development can still fail because Chromatic builds it in production mode. A visual difference, a missing project token, and a pending GitHub check each need different remedies.

This guide follows Chromatic’s official [CLI documentation](https://www.chromatic.com/docs/cli/), [GitHub Actions guide](https://www.chromatic.com/docs/github-actions/), and [CI troubleshooting guide](https://www.chromatic.com/docs/ci/). Action tags, defaults, and service behavior can change, so check those pages when updating an existing workflow.

1. Find the failing layer from the job log

Open the failed GitHub Actions run and expand the first step that reports an error. Record the exact error text, step name, commit SHA, and Chromatic build URL if one was produced. Later errors may be consequences of the first failure.

First failing step or message Likely layer Start here
Dependency installation GitHub Actions or project setup Check the package manager, lockfile, Node version, working directory, and install output.
Failed to build Storybook Production build Reproduce the production Storybook build locally and fix its compiler or configuration error.
Failed to extract stories from your Storybook Storybook runtime or story extraction Build and open Storybook locally; inspect the browser console for runtime errors.
Cannot run a build with no stories Story discovery or snapshots disabled Confirm the build contains stories and that snapshots are not globally disabled.
Token, authentication, or project error Chromatic setup Check the project token secret and that it belongs to this Storybook project.
Git log, detached HEAD, or wrong baseline Git checkout context Inspect installed Git, checkout history, ref, branch, and commit SHA.
Visual changes found Review outcome Open the Chromatic build and review the changes; this is not automatically a build error.
Required check remains pending GitHub status reporting Confirm the workflow ran for this commit and the intended Chromatic check is enabled.
Build verification timed out Server, connection, or timeout Determine whether the Storybook server stopped, connectivity was lost, or the configured limit was too short.

Chromatic’s CLI documents exit codes 0 (OK), 1 (BUILD_HAS_CHANGES), 2 (BUILD_HAS_ERRORS), 3 (BUILD_FAILED), 4 (BUILD_NO_STORIES), and 5 (BUILD_WAS_LIMITED). A nonzero code alone does not identify the cause: pair it with the exact message and build result. The GitHub Action also provides outputs such as code, build URLs, and snapshot or change counts; use those to link reports, but inspect the build itself before deciding what to fix. See the [CLI reference](https://www.chromatic.com/docs/cli/) and [action inputs and outputs](https://www.chromatic.com/docs/github-actions/).

2. Check out the repository and authenticate the action

A basic workflow checks out the repository, installs dependencies, and runs Chromatic with the project token held in a GitHub Actions secret. Save the token as CHROMATIC_PROJECT_TOKEN in the repository’s Actions secrets, then reference it in the workflow. Do not commit the token or print it in logs: anyone with a plaintext token can run builds against that project.

name: Chromatic
on: push
jobs:
  chromatic:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repository
        uses: actions/checkout@v4
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: Install dependencies
        run: npm ci
      - name: Run Chromatic
        uses: chromaui/action@latest
        with:
          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}

This is a starting template, not a version recommendation: confirm current action tags and compatibility in Chromatic’s [GitHub Actions guide](https://www.chromatic.com/docs/github-actions/) before adopting it. The documented update choices are @latest for automatic updates, @vX to follow a major version, or @vX.Y.Z to pin a version. Follow your team’s dependency update policy.

Token and repository checks

  • Verify the secret name in the workflow matches the name configured in repository settings.
  • Ensure the workflow runs in the repository that owns the secret. Forked repositories do not receive repository-level secrets.
  • Confirm the token belongs to the intended Chromatic project, especially in a monorepo with multiple Storybooks.
  • Check the job’s working directory and make sure it contains the intended package.json and build script.

If dependencies install but the action cannot find or build Storybook, check the package directory and script before changing authentication. In a monorepo, configure the correct working directory and project token. If an earlier step already built Storybook, Chromatic’s action can use storybookBuildDir to point at that output directory.

3. Reproduce Storybook’s production build locally

Chromatic builds Storybook in production mode. Consequently, a Storybook that runs in the development server may still fail during Chromatic’s build. Run the same production build locally, fix the underlying error, and serve the generated output to reproduce what Chromatic sees. Use the build script your project actually defines; build-storybook is a common example, not a universal script name.

npm ci
npm run build-storybook
npx http-server storybook-static

If http-server is not installed in your project, use your existing static file server. Check the terminal output for compiler and configuration errors, then open the served Storybook and inspect the browser console for runtime errors.

Story extraction and no-story errors

  • Failed to extract stories from your Storybook: build Storybook locally, open it in a browser, and check the console. A runtime error in Storybook can prevent Chromatic from extracting stories.
  • Cannot run a build with no stories: confirm your stories are included in Storybook’s configuration and that the built output contains them. Check for a top-level chromatic: { disableSnapshot: true } setting or other snapshot exclusions that disable all intended snapshots; remove the broad setting or re-enable the stories that should be captured.

For additional reproduction detail, Chromatic documents --dry-run, --debug, and --diagnostics-file:

npx chromatic --dry-run --debug --diagnostics-file

Review and redact tokens or sensitive project details from diagnostic output before sharing it. See Chromatic’s [CLI troubleshooting](https://www.chromatic.com/docs/cli/) and [Quickstart troubleshooting](https://www.chromatic.com/docs/quickstart/).

4. Restore Git history and the intended branch context

Chromatic uses Git metadata to associate builds with commits and find visual baselines. If the log reports a Git command error, a detached HEAD, or an unexpected baseline, inspect the checkout rather than guessing which branch value to set.

git --version
git status --short --branch
git log -n 1 --oneline
git rev-parse HEAD

Run these in the same job directory where Chromatic runs. Confirm that Git is installed, .git is present, and the checked-out commit is the one the workflow should test. Chromatic’s CI guide states Docker images need Git 2.28.0 or later; check the current guide if using a container image.

Detached HEAD, pull requests, and baselines

A detached HEAD can occur in GitHub Actions with a pull_request trigger or when checkout lacks an explicit ref. Inspect the actual checked-out SHA and ref in the failed run. Chromatic recommends push events in its GitHub Actions guidance because pull request workflows may use an ephemeral merge commit, which can lead to unexpected commit association or baselines in some setups. This is a tradeoff: choose the trigger that matches your review process, then verify Chromatic associates the build with the intended commit.

If commit association is wrong, compare the commit shown on the Chromatic build page with the GitHub commit. Check that the project is linked to the intended Git provider and that the checkout context matches the repository. If you manually supply CHROMATIC_SHA, CHROMATIC_BRANCH, or CHROMATIC_SLUG, Chromatic’s CI guidance says to set all three together and ensure they refer to the same intended repository, commit, and branch.

5. Decide whether visual changes should fail the job

Visual differences mean Chromatic found changes to review; they do not necessarily mean Storybook failed to build. The GitHub Action’s documented default for exitZeroOnChanges is true, so detected changes can leave the action successful. To make unreviewed visual changes fail a required job, set it to false:

- name: Run Chromatic
  uses: chromaui/action@latest
  with:
    projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
    exitZeroOnChanges: false

Choose based on the team’s merge policy:

Setting Effect Use when
exitZeroOnChanges: true (documented default) Detected changes do not make the action fail solely because of those changes. Visual review is tracked in Chromatic but should not make this action fail automatically.
exitZeroOnChanges: false Detected changes can fail the action. The visual check is intended to block merging until changes are reviewed.

Review the build and accept intended changes or reject unexpected ones, then update the implementation as appropriate. exitZeroOnChanges does not accept changes. autoAcceptChanges does: reserve it for a deliberately chosen baseline branch and an explicit review policy, not as a general way to make failures disappear. See Chromatic’s [configuration reference](https://www.chromatic.com/docs/configure/) and [action guide](https://www.chromatic.com/docs/github-actions/).

6. Resolve a pending or unsynchronized pull request check

A required check that remains pending may never have reported a result. Check three things: the action ran for the commit GitHub is waiting on; the Chromatic project is linked to the intended Git provider; and the required check type, such as UI Test or UI Review, is enabled in Chromatic project settings. A conditionally skipped action step or disabled check can leave a required status pending.

If a skipped build should resolve the status, Chromatic recommends using its --skip behavior instead of skipping the CI step itself. If changes are awaiting visual review, the check may remain pending until the review is complete. Chromatic states that check status is driven by the build result; it cannot be programmatically marked passed independently of that result. Read the [mandatory PR checks guide](https://www.chromatic.com/docs/mandatory-pr-checks/) before changing branch protection.

For statuses attached to the wrong commit, compare the SHA on the Chromatic build with GitHub’s commit. An ephemeral pull request merge commit or mismatched manual SHA, branch, and repository slug can explain a mismatch. Ensure the action runs for every commit that GitHub requires a status for.

7. Diagnose timeouts and intermittent failures

For Build verification timed out, first determine whether Storybook’s server stopped early or the network connection was interrupted. Increasing a timeout helps only when work is still progressing but the configured limit is insufficient. Chromatic documents STORYBOOK_BUILD_TIMEOUT and CHROMATIC_TIMEOUT as environment variables for increasing allowed time; consult its current [timeout FAQ](https://www.chromatic.com/docs/faq/build-verification-timeout/) for the supported configuration and apply the smallest limit that fits observed build duration.

For large or slow Git operations, the configuration reference lists gitTimeout with a documented 20-second default for an individual Git operation. Increase it only when the log points to a slow Git operation. If the failure looks like a transient service or connection interruption, keep the run URL and logs, then rerun once to see whether the failure is reproducible. Repeated failures at the same step usually point to a persistent setup or build issue rather than a timeout value.

8. Improve workflow reliability and control cost

  • Keep the workflow reproducible: use the repository’s lockfile-driven install, explicit project directory, and a consistent Node version. Align the job with the build that developers run locally.
  • Preserve Git context: retain the checkout and history required to associate commits and baselines; avoid manually overriding only one of the SHA, branch, and slug values.
  • Make check policy explicit: decide whether visual changes fail the job, enable the corresponding Chromatic check, and avoid conditionally skipping the whole step when GitHub requires its status.
  • Retain diagnostics: keep the build URL and relevant error lines with the failed run. Share diagnostic files only after removing tokens and private project information.
  • Control CI spend: avoid duplicate builds from overlapping triggers where your workflow does not need them, and use intentional skip behavior for commits that should not produce a visual build. Verify the resulting status still satisfies branch protection.

Chromatic’s documented action outputs can help you report the build URL, code, and snapshot or change counts in later workflow steps. These values make failures easier to inspect but do not replace a review of the Chromatic build or a correct required-check configuration.

9. Troubleshooting checklist

Symptom Cause to verify Fix
Action cannot authenticate Missing, misspelled, unavailable, or mismatched token secret Configure the repository secret, use its exact name, and check that the token belongs to this project. Fork workflows will not receive repository secrets.
Development Storybook works; Chromatic build fails Production-only compiler, configuration, or dependency error Run the production build locally and fix the first build error.
Stories cannot be extracted Storybook runtime error Serve the local production output and inspect the browser console.
No stories found Wrong story configuration or snapshots disabled Check story discovery and remove unintended global snapshot disabling.
git log -n 1 fails Git missing or checkout/history unavailable Install or include supported Git and verify the job has a repository checkout with usable history.
Detached HEAD or wrong baseline Pull request merge ref or incorrect checkout context Inspect actual SHA/ref, use the intended checkout context, and check commit association before setting Chromatic Git variables.
Visual changes do not fail CI exitZeroOnChanges remains true Set it to false if review must block the job; review changes in Chromatic.
Required status stays pending Step skipped, check disabled, build awaiting review, or status tied to another SHA Run the action for the required commit, enable the check, use Chromatic skip behavior where appropriate, and compare SHAs.
Verification timeout Server crash, lost connection, or insufficient limit Inspect the failed step; increase the documented timeout only if the process is progressing and needs more time.
Failure appears intermittent Transient connectivity or service failure Preserve the build URL and logs, rerun, and compare the failing step to distinguish a transient event from a reproducible defect.

Or skip the browser setup

If a separate workflow needs a website screenshot while you debug Storybook, ScreenshotNeo can return an image or PDF from one GET request. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots, and 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000. Learn more at ScreenshotNeo. Sign up for 1,000 free screenshots a month, with no card required.

FAQ

Does a Chromatic visual difference mean the GitHub Actions build is broken?

No. It can be a successful build with changes awaiting review. The action’s exitZeroOnChanges setting controls whether those differences alone fail the job.

Why does Chromatic fail when Storybook works locally?

Chromatic builds Storybook in production mode. A development server can work while a production-only compiler or runtime error remains.

Should I use push or pull_request?

Use the trigger that matches your workflow and check how it maps to the commit Chromatic should test. Chromatic notes that pull request merge commits can complicate baseline association in some setups; validate the actual SHA and ref.

Can I force a pending Chromatic status to pass?

The status follows the Chromatic build result. Make sure the build runs for the required commit and the appropriate check is enabled, then resolve any visual review still awaiting approval.

Where should I share a Chromatic token when asking for help?

Do not share it in logs, commits, or public reports. Share the relevant error, build URL, and redacted diagnostics instead.