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

# blobhub workflow check

> Run the platform checker against what is already deployed, and print its events

`check` asks the platform to validate the workflow definitions on the revision and prints what it says back. It
uploads nothing and compiles nothing — it checks what is deployed right now, which may or may not be what your
working tree holds.

Reach for it after a [`push`](/cli/workflow/commands/push), which never checks, or after a
[`deploy`](/cli/workflow/commands/deploy) that reported a failure and stopped at the first one.

## Synopsis

```bash theme={null}
blobhub workflow check -f <manifest> [--definition <alias>]
```

| Flag           | Default                          | Description                      |
| -------------- | -------------------------------- | -------------------------------- |
| `--file`, `-f` | required                         | Path to the workflow manifest.   |
| `--definition` | every definition in the manifest | Limit to this alias. Repeatable. |

## What it does

1. Resolves the blob and revision. This is a read, so phase `commit` is allowed alongside `draft` and `managed`.
2. Lists the revision's definitions and matches the manifest against them.
3. Calls `check_definition` for each manifest entry that is **workflow**-category **and** present on the
   revision. Playground entries are skipped, and so is any entry the revision does not have — both without an
   output line of their own.
4. If every check passed, prints one line per definition with each event indented beneath it, as
   `type: component_id: message` — `component_id` appears only on the events that carry one:

```text theme={null}
workflow/checkout_flow: success
  info: Verification completed. The flow is ready to be executed
```

That `info` event is what a clean definition looks like: the platform emits it when it found nothing else to
say. Under `--json` the payload carries `status`, `checked` — each entry with its `status` and the checker's raw
`events` — and `drift`, alongside the envelope's `schema_version`.

If any check failed, none of that is printed. The failures are collected into a single `CHECK_FAILED` error on
stderr, naming each failing definition and its events, and the command exits `1`:

```text theme={null}
error: CHECK_FAILED: check_definition failed for: checkout_flow: error: `flow.start` component is not found. Execution does not have a starting point
```

`deploy` reports the first failing check; `check` reports all of them. That is the reason to re-run it after a
failed deploy.

## HTTP `200` does not mean the check passed

`check_definition` answers `200 OK` with `{"status": "failure", "events": [...]}` in the body. The CLI keys off
the body's `status` and never off the HTTP status — a tool that gates on the HTTP status alone reports a broken
workflow as valid.

This is worth remembering if you drive the API directly. It is not an error path: a failing check is a
successful call whose result is "no".

## What the checker actually validates

Structure, and only structure:

| Checked                                                                                                                                           | Not checked                                                                 |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| Every component carries `id`, `type`, `name` and `category` — the keys `upload_definition` never checks.                                          | The **types of port values**. A port holding the wrong kind of data passes. |
| Exactly one `flow.start` component. Zero and two are both errors.                                                                                 | The document's own `type` and `version`.                                    |
| Connection consistency: every `source_id`/`target_id` resolves to a component, and `data`/`provider` components have an inbound connection.       | Cycles in the graph.                                                        |
| Per-component: the type exists in the platform's manifest, and every port the manifest marks required is filled either inline or by a connection. | The `code` itself — it is never parsed, let alone executed.                 |

A passing check therefore means the definition is *structurally* runnable, not that it works. Compile-time
guarantees about your Python come from [`build`](/cli/workflow/commands/build); runtime behaviour comes from
running it.

**`success` can still carry events.** Only an `error` event decides failure — `warning` and `info` events travel
in the same list and leave the status alone. Read the events on a passing check rather than stopping at the
status line.

**A freshly created definition legitimately fails.** `create_definition` writes an empty stub with no components
at all, so it has no `flow.start` and the checker says so. That is the expected answer for a definition nothing
has been uploaded into yet, not a defect in the CLI or the platform.

## Errors

| Code                                                                                               | When                                                                                                                                                                              |
| -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CHECK_FAILED`                                                                                     | At least one definition's check returned body `status: "failure"`. The message carries each failing definition's events, or `no events reported` when the platform returned none. |
| `MANIFEST_NOT_FOUND`, `MANIFEST_INVALID`, `MANIFEST_TYPE_MISMATCH`, `MANIFEST_VERSION_UNSUPPORTED` | The manifest is absent or unusable.                                                                                                                                               |
| `DEFINITION_ALIAS_INVALID`, `DEFINITION_CATEGORY_UNKNOWN`, `DEFINITION_NOT_ACCESSIBLE`             | An alias fails the pattern; a category cannot be inferred or contradicts the document; a `--definition` alias is not in the manifest.                                             |
| `BLOB_NOT_ACCESSIBLE`, `BLOB_NOT_WORKFLOW`                                                         | The blob is absent or unreachable with this key, or is not a workflow blob.                                                                                                       |
| `REVISION_NOT_ACCESSIBLE`, `REVISION_NOT_WRITABLE`                                                 | The revision is unreachable, or its status is not `ready` — or its phase is none of `draft`, `commit`, `managed`.                                                                 |
| `FORMAT_UNSUPPORTED`, `FORMAT_PARSE_ERROR`                                                         | A `source` has an unsupported extension, or does not parse — `check` reads each local document to resolve its category.                                                           |
| `CREDENTIALS_NOT_FOUND`, `PROFILE_NOT_FOUND`, `INSECURE_CREDENTIALS_PERMISSIONS`                   | No usable credential, or a credentials file the CLI refuses to read.                                                                                                              |
| `API_RATE_LIMITED`, `API_TRANSIENT_ERROR`, `API_NETWORK_ERROR`                                     | A call failed after its retries.                                                                                                                                                  |
| `DEFINITION_LIST_TRUNCATED`                                                                        | Advisory, on stderr: the listing may be incomplete. The exit code stays `0`.                                                                                                      |

A manifest entry that is not on the revision is not an error here — `check` has nothing to check and moves on.
[`diff`](/cli/workflow/commands/diff) is what reports that gap.

Every code above, with its remediation, is in [Error codes](/cli/error-codes).

## See also

* [`blobhub workflow deploy`](/cli/workflow/commands/deploy) — runs this same check on what it uploaded.
* [`blobhub workflow diff`](/cli/workflow/commands/diff) — whether the deployed definition is the one you have.
* [Check Definition](/blob-types/workflow/operations/check-definition) — the operation, and its event shapes.
* [Workflow definition format](/blob-types/workflow/workflows/definition-format) — `flow.start`, connections and
  component types, which is what the checker is reading.
