> ## Documentation Index
> Fetch the complete documentation index at: https://docs.testdino.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Re-run failed Playwright tests

> Re-run only the failed or flaky test cases from a finished Playwright run, on the same commit or the latest code.

export const VideoSchema = ({name, description, thumbnailUrl, uploadDate, duration, contentUrl, embedUrl}) => {
  const schema = {
    "@context": "https://schema.org",
    "@type": "VideoObject",
    name,
    description,
    thumbnailUrl,
    uploadDate,
    ...duration ? {
      duration
    } : {},
    ...contentUrl ? {
      contentUrl
    } : {},
    ...embedUrl ? {
      embedUrl
    } : {},
    publisher: {
      "@type": "Organization",
      name: "TestDino",
      logo: {
        "@type": "ImageObject",
        url: "https://docs.testdino.com/logo/light.svg"
      }
    }
  };
  return <script type="application/ld+json" dangerouslySetInnerHTML={{
    __html: JSON.stringify(schema)
  }} />;
};

<VideoSchema name="Re-run Only Failed Playwright Tests in CI" description="Re-run only the failed Playwright test cases from a finished TestDino run with one click, an API call, or an AI prompt." thumbnailUrl="https://i.ytimg.com/vi/cLSwTSYrAjA/maxresdefault.jpg" uploadDate="2026-10-07T00:00:00+00:00" contentUrl="https://www.youtube.com/watch?v=cLSwTSYrAjA" embedUrl="https://www.youtube.com/embed/cLSwTSYrAjA" />

Re-run takes a finished test run and executes only the test cases that failed or were flaky in it. Start one from the test run page, a terminal, or an AI agent.

For a test run from GitHub Actions, **This commit** re-runs the failed jobs inside the original GitHub run, so that run's own red check can turn green. No workflow change is needed for it.

<Note>
  Re-run requires the `@testdino/playwright` npm package at 2.7.0 or later, and Playwright 1.56 or later. Check yours with `npm ls @testdino/playwright`. An earlier version exits with `error: unknown option '--rerun'`.

  Re-running inside the original GitHub run needs 2.7.8 or later. On an earlier version the failed jobs still re-run, in full.
</Note>

<iframe className="w-full rounded-lg h-[500px]" src="https://www.youtube.com/embed/cLSwTSYrAjA" title="Re-run only failed Playwright tests in CI" frameBorder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; embedding" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen />

## Quick Reference

| Topic | Link | Best for |
| :- | :- | :- |
| Dashboard button | [Start a re-run from the dashboard](#start-a-re-run-from-the-dashboard) | A test run you are already reading |
| Scope the selection | [Choose which test cases run](#choose-which-test-cases-run) | Narrowing to your own failures |
| Same or new code | [Choose which code runs](#choose-which-code-runs) | Telling a flaky test from a real failure |
| Turn the red check green | [Re-run inside the original GitHub run](#re-run-inside-the-original-github-run) | A red commit you want green without a new run |
| Tags | [Add tags to a re-run](#add-tags-to-a-re-run) | Finding a re-run later |
| Repository setup | [Enable the dashboard button](#enable-the-dashboard-button) | Turning on one-click re-runs |
| Terminal | [Re-run from the command line](#re-run-from-the-command-line) | CI without GitHub, or scripting |
| Agents | [Re-run from an AI agent](#re-run-from-an-ai-agent) | Agent-driven fix loops |

## Start a re-run from the dashboard

**Re-run** sits in the action row right of the tab strip on a test run's page, next to **Debug with AI**. It appears once the test run has finished and carries at least 1 failed or flaky test case. A test run reporting `passed` still shows it when the run carries flaky test cases.

<img src="https://tdstorageus.blob.core.windows.net/public/docs/guides/debug-failures/rerun-failed-tests/rerun-panel.webp" alt="Re-run panel open on a test run page showing the Failed scope, the selected count, the Run against choice, the workflow, and the Re-run button" />

The panel shows the count that will run as `7 of 9 selected`, the code choice, and the workflow that will run it. The button states what happens:

| Button reads | Meaning |
| :- | :- |
| `Re-run 6 failed tests` | The scope's test cases, on the original commit |
| `Re-run 11 tests on latest` | The scope's test cases, on the branch tip |
| `Re-run 3 selected tests` | A hand-picked subset |
| `Re-run failed jobs in full` | The failed jobs, inside the original GitHub run, with every test case in them |
| `Select tests to re-run` | Nothing is ticked, so the button is disabled |

The new test run appears in the run list once CI picks it up, marked **Re-run of #N** and linked to the run it came from. It carries the original test run's run-level tags, so it shows up under the same tag filters. The original test run lists its re-runs under its header. See [Test Runs](/platform/playwright-test-runs#re-runs).

## Choose which test cases run

| Choice | Selects |
| :- | :- |
| **Failed** | Test cases that failed, including timeouts. The default. |
| **Flaky** | Test cases that passed only after a retry. |
| **Both** | Failed and flaky together. |
| **Custom** | Test cases you tick by hand. |

**Custom** appears when there is more than 1 test case to choose between. On large test runs it adds a search box and a group-by choice for spec file, failure reason, or browser.

<img src="https://tdstorageus.blob.core.windows.net/public/docs/guides/debug-failures/rerun-failed-tests/custom-selection.webp" alt="Re-run panel in Custom scope showing hand-ticked test cases, the search box, and the group-by choice" />

## Choose which code runs

**Run against** offers 2 options, and they answer different questions:

| Option | What runs | What the result tells you |
| :- | :- | :- |
| **This commit** | The commit the original test run used | Still failing is a real failure. Passing now means the test case is flaky. |
| **Latest on `<branch>`** | The current branch tip | Whether a fix that landed since works. |

On a test run from GitHub Actions, **This commit** re-runs inside the original GitHub run instead of starting a new one. See [Re-run inside the original GitHub run](#re-run-inside-the-original-github-run). **Latest** always starts a new workflow run.

For a re-run that starts a new workflow run, **This commit** is unavailable, with the reason shown, when the original test run recorded no commit or only an abbreviated one, or when the workflow does not declare `testdino_rerun_sha`. A test run made outside CI with uncommitted changes keeps **This commit**, with a note that the re-run uses the commit as pushed, without those changes.

**Latest** is unavailable when the test run recorded no branch or the branch is gone; the re-run then dispatches on the default branch, still pinned to the original commit. When the branch tip is still the original commit, the panel says so: both options run the same code.

## Re-run inside the original GitHub run

When the test run came from GitHub Actions, **This commit** re-runs its failed jobs as a new attempt of that same GitHub run. If they pass, that run and the commit's check turn green, with no second workflow run in the commit's check list. The panel says so before you click:

> The failed jobs run again inside GitHub run #124. If they pass, that run turns green. Only the failed tests run again.

No workflow change is needed. **This commit** takes this path when all of these hold:

* The test run came from a GitHub Actions run in the repository connected to the project.
* The TestDino GitHub App has the **Actions** permission.
* The scope is **Failed** or **Both**. **Flaky** and **Custom** start a new workflow run instead.

The click is refused, with the reason, while the GitHub run is still in progress or once it is more than 30 days old. Use **Latest** to start a new workflow run instead.

### Run only the failed test cases in each job

Each retried job runs only the test cases that failed in it when the job runs `npx tdpw test` with `@testdino/playwright` 2.7.8 or later. Your job's command stays the same.

Otherwise every test case in the failed jobs runs again, and the button reads `Re-run failed jobs in full`. The panel shows **Every test in the failed jobs will run again** with the change to make. The job log prints the reason on each full run.

| Case | What to do |
| :- | :- |
| The workflow runs `npx playwright test` | Switch the command to `npx tdpw test`. |
| `@testdino/playwright` is older than 2.7.8 | Update the package. |
| A test case in the job has no result from the earlier attempt, after a cancelled shard, a crashed job, or a time-out | Nothing to do. The whole job runs. |
| The same Playwright project runs in more than 1 job, such as an operating system or Node version matrix | Nothing to do. A browser matrix built from Playwright projects is unaffected. |
| The re-run was started from GitHub's own **Re-run failed jobs** button | Start the re-run from TestDino instead. |

### How a re-run counts in your metrics

A re-run is left out of run-level figures: test run count, pass rate, and average duration. Its test cases still appear in test-level views, and it is billed like any test run.

## Add tags to a re-run

A re-run keeps the original test run's run-level tags. A dashboard re-run starts as a `workflow_dispatch` with no pull request context, so tags your workflow builds from the pull request still arrive, copied from the original. No workflow change is needed for this.

To label a single re-run, type tags into **Extra tags** in the panel, separated by commas, for example `hotfix-retry`. They are added on top of the inherited tags:

* At most 10 tags per re-run.
* Letters, digits and `. _ : / @ + -` only, starting with a letter or digit.
* When the combined list goes over the 50-tag limit per test run, the re-run's own tags, extra tags included, are kept and the inherited ones are trimmed.

Extra tags need the `testdino_rerun_tags` workflow input (see [Enable the dashboard button](#enable-the-dashboard-button)) and `@testdino/playwright` 2.7.6 or later. On a workflow without the input, the panel refuses tags before anything starts.

A re-run inside the original GitHub run keeps that run's tags and cannot add more. To tag a re-run, pick **Latest** to start a new workflow run.

## Enable the dashboard button

Re-running inside the original GitHub run needs no workflow inputs. The rest of this section is for the other paths: **Latest**, the **Flaky** and **Custom** scopes, and any test run that did not come from GitHub Actions.

Connect GitHub to the project in Project settings, under Integrations, and grant the TestDino GitHub App permission to start workflows. Then declare the re-run inputs on a workflow. Either shape works, because TestDino offers any active workflow that declares `testdino_rerun_from`:

| Choice | Pick it when |
| :- | :- |
| **Existing workflow** | You want one workflow definition to maintain. It keeps its normal triggers and gains a re-run path. |
| **Separate workflow** | You want re-runs isolated: their own logs, their own concurrency, no change to the workflow CI already runs. |

<Tabs>
  <Tab title="Existing workflow">
    Add `workflow_dispatch` and the inputs to the workflow you already run Playwright with. The `if [ -n "$TD_RERUN_FROM" ]` guard is what keeps a normal push unchanged: on a push the input is empty, so no re-run arguments are added.

    ```yaml .github/workflows/playwright.yml theme={null}
    on:
      push:
      workflow_dispatch:
        inputs:
          testdino_rerun_from:
            required: true
          testdino_rerun_scope:
            default: failed
          testdino_rerun_test_ids:
            required: false
          testdino_rerun_exclude_ids:
            required: false
          testdino_rerun_sha:
            required: false
          testdino_rerun_tags:
            required: false

    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
            with:
              ref: ${{ inputs.testdino_rerun_sha || github.sha }}
          - uses: actions/setup-node@v4
            with:
              node-version: 22
          - run: npm ci
          - name: Run tests
            env:
              TESTDINO_TOKEN: ${{ secrets.TESTDINO_TOKEN }}
              TD_RERUN_FROM: ${{ inputs.testdino_rerun_from }}
              TD_RERUN_SCOPE: ${{ inputs.testdino_rerun_scope }}
              TD_RERUN_TEST_IDS: ${{ inputs.testdino_rerun_test_ids }}
              TD_RERUN_EXCLUDE_IDS: ${{ inputs.testdino_rerun_exclude_ids }}
              TD_RERUN_TAGS: ${{ inputs.testdino_rerun_tags }}
            shell: bash
            run: |
              args=()
              if [ -n "$TD_RERUN_FROM" ]; then
                args+=(--rerun "${TD_RERUN_SCOPE:-failed}" --from-run "$TD_RERUN_FROM")
                if [ -n "$TD_RERUN_TEST_IDS" ]; then
                  args+=(--test-ids "$TD_RERUN_TEST_IDS")
                fi
                if [ -n "$TD_RERUN_EXCLUDE_IDS" ]; then
                  args+=(--exclude-ids "$TD_RERUN_EXCLUDE_IDS")
                fi
                if [ -n "$TD_RERUN_TAGS" ]; then
                  args+=(--rerun-tags "$TD_RERUN_TAGS")
                fi
              fi
              npx tdpw test "${args[@]}"
    ```
  </Tab>

  <Tab title="Separate workflow">
    A workflow that only ever runs a re-run needs no guard: `workflow_dispatch` is its only trigger and `testdino_rerun_from` is required, so the input is always present.

    ```yaml .github/workflows/rerun.yml theme={null}
    name: Re-run failed tests

    on:
      workflow_dispatch:
        inputs:
          testdino_rerun_from:
            required: true
          testdino_rerun_scope:
            default: failed
          testdino_rerun_test_ids:
            required: false
          testdino_rerun_exclude_ids:
            required: false
          testdino_rerun_sha:
            required: false
          testdino_rerun_tags:
            required: false

    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
            with:
              ref: ${{ inputs.testdino_rerun_sha || github.sha }}
          - uses: actions/setup-node@v4
            with:
              node-version: 22
          - run: npm ci
          - name: Run the selected tests
            env:
              TESTDINO_TOKEN: ${{ secrets.TESTDINO_TOKEN }}
              TD_RERUN_FROM: ${{ inputs.testdino_rerun_from }}
              TD_RERUN_SCOPE: ${{ inputs.testdino_rerun_scope }}
              TD_RERUN_TEST_IDS: ${{ inputs.testdino_rerun_test_ids }}
              TD_RERUN_EXCLUDE_IDS: ${{ inputs.testdino_rerun_exclude_ids }}
              TD_RERUN_TAGS: ${{ inputs.testdino_rerun_tags }}
            shell: bash
            run: |
              args=(--rerun "${TD_RERUN_SCOPE:-failed}" --from-run "$TD_RERUN_FROM")
              if [ -n "$TD_RERUN_TEST_IDS" ]; then
                args+=(--test-ids "$TD_RERUN_TEST_IDS")
              fi
              if [ -n "$TD_RERUN_EXCLUDE_IDS" ]; then
                args+=(--exclude-ids "$TD_RERUN_EXCLUDE_IDS")
              fi
              if [ -n "$TD_RERUN_TAGS" ]; then
                args+=(--rerun-tags "$TD_RERUN_TAGS")
              fi
              npx tdpw test "${args[@]}"
    ```
  </Tab>
</Tabs>

TestDino reads the workflow files on the test run's branch and offers only the ones that declare these inputs. A workflow file that is not on that branch cannot run the re-run, and the panel names it under the workflow picker.

| Input | Required? | Without it |
| :- | :- | :- |
| `testdino_rerun_from` | Yes | The workflow is not offered for re-runs. |
| `testdino_rerun_scope` | Recommended | Only **Failed** can be sent. |
| `testdino_rerun_test_ids` and `testdino_rerun_exclude_ids` | For Custom | The workflow cannot receive a hand-picked list, and the panel says so. |
| `testdino_rerun_sha` | For **This commit** | Only **Latest** can be sent. |
| `testdino_rerun_tags` | For **Extra tags** | The panel refuses tags for this workflow. |

<Warning>
  A workflow that declares `testdino_rerun_sha` without passing it to `checkout` reports a same-commit re-run while running current code. The `ref:` line above is what makes the pin real.
</Warning>

The workflow file itself always comes from the branch tip, so a same-commit re-run runs the original test code under your current pipeline definition.

## Re-run from the command line

Without a GitHub connection the panel gives you this command under **Run manually**, with the id lists filled in:

```bash theme={null}
npx tdpw test --rerun failed --from-run test_run_a66fa0ee4f7a28ef5986e907
```

Before running anything, the CLI checks the selection against the code you have checked out. Test cases renamed, moved, or deleted since the original test run, or filtered out by your Playwright arguments such as `--project`, are skipped. The warning names them (up to 10) and the original test run by its number and commit, with a link to it. To run them unchanged, re-run on **This commit** or check out that commit. If none of them match, the CLI stops with an error rather than reporting a green test run that executed nothing.

## CLI flags

| Flag | Description |
| :- | :- |
| `--rerun <scope>` | `failed`, `flaky`, or `failed-and-flaky`. |
| `--from-run <runId>` | The test run to re-run from. Required with `--rerun`. |
| `--test-ids <ids>` | Comma-separated test case ids to run, overriding the scope. |
| `--exclude-ids <ids>` | Comma-separated test case ids to drop from the scope. |
| `--rerun-tags <tags>` | Comma-separated run tags added to the re-run, on top of its own and inherited tags. Falls back to `TESTDINO_RERUN_TAGS`. Refused without `--rerun`. Requires 2.7.6 or later. |

`--rerun` is refused alongside a Playwright argument that would fight the selection: `--grep`, `--grep-invert`, `--last-failed`, `--test-list`, and `--shard`. Full flag reference in [`@testdino/playwright`](/cli/testdino-playwright-nodejs).

## Re-run from an AI agent

| Tool | Does |
| :- | :- |
| `get_rerun_selection` | Resolves which test cases would run, plus the command. Nothing starts. |
| `rerun_test` | Starts the GitHub Actions workflow for that selection. |

`rerun_test` runs only after you have seen the selection and said yes, so an agent cannot spend CI minutes on its own. Parameters for both are in the [MCP tools reference](/mcp/tools-reference).

## Troubleshooting

<AccordionGroup>
  <Accordion title="error: unknown option '--rerun'">
    The project resolves `npx tdpw` to a CLI older than 2.7.0, which passes the flag through to Playwright. Upgrade `@testdino/playwright` to 2.7.0 or later.
  </Accordion>

  <Accordion title="The re-run ran every test, not just the failures">
    The job log line that starts with `TestDino: running the full command on this GitHub retry` gives the reason. The usual causes are a workflow running `npx playwright test` instead of `npx tdpw test`, or `@testdino/playwright` older than 2.7.8. A test case with no result from the earlier attempt, or the same Playwright project running in more than 1 job, also runs the whole job, and no setting changes that. See [Run only the failed test cases in each job](#run-only-the-failed-test-cases-in-each-job).
  </Accordion>

  <Accordion title="No workflow is offered in the panel">
    No workflow on the branch declares a `testdino_rerun_from` input, or the TestDino GitHub App lacks permission to start workflows. The panel falls back to the terminal command. See [Enable the dashboard button](#enable-the-dashboard-button).
  </Accordion>

  <Accordion title="Results are still being processed">
    The test run finished seconds ago and its results are still being read. The panel updates itself; the CLI waits. This is not the same as having nothing to re-run.
  </Accordion>

  <Accordion title="Some test cases are listed as needing a manual run">
    Playwright identifies a test case by its full name, splitting the parts on `›` and trimming each one, with no escape for either. A title containing that separator, or starting or ending with a space, a non-breaking space, or a line break, cannot be requested exactly.

    Those test cases are listed separately everywhere the selection appears, and the selected count excludes them, so a re-run never reports success for a test case it could not execute. Run them with your usual Playwright command, or rename the test case.
  </Accordion>

  <Accordion title="This commit is unavailable">
    The original test run recorded no commit or only an abbreviated one, so there is no commit to pin to, or the workflow does not declare `testdino_rerun_sha`. The panel shows which. Use **Latest**, or add `testdino_rerun_sha` to the workflow and pass it to `checkout` as shown in [Enable the dashboard button](#enable-the-dashboard-button).
  </Accordion>

  <Accordion title="GitHub shows the branch tip for a This commit re-run">
    GitHub starts a dispatched workflow from a branch, never a single commit, so the workflow run page shows the branch tip. The `ref:` line in `checkout` then switches the job to the commit you picked. The `HEAD is now at` line in the checkout step's log and the commit on the new test run in TestDino both show the pinned commit.

    To name the pinned commit on GitHub too, add a top-level `run-name` next to `name:` in the workflow. Other test runs keep their default title.

    ```yaml theme={null}
    run-name: ${{ inputs.testdino_rerun_from != '' && format('TestDino re-run @ {0}', inputs.testdino_rerun_sha || 'branch tip') || '' }}
    ```
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Debug with AI" icon="wand-magic-sparkles" href="/guides/debug-playwright-failures/debug-with-ai">
    Hand a failure to your coding agent from the same action row.
  </Card>

  <Card title="Flaky tests" icon="shuffle" href="/guides/playwright-flaky-test-detection">
    How TestDino decides a test case is flaky.
  </Card>

  <Card title="Test run details" icon="play" href="/platform/playwright-test-runs">
    The run page this panel opens from.
  </Card>

  <Card title="GitHub Actions" icon="github" href="/guides/playwright-github-actions">
    Reporting Playwright results from GitHub Actions.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.