# Debugging

URL: /code/cli/guides/debugging · Id: `page:code/cli/guides/debugging`

> Every response names its request, and the request log follows it through every check, the Action it started, the Events it emitted and the logs it wrote.

Every response from [api.sb](/code/platform/api-sb) carries a request id. From that id, the request log shows each check, the [Action](/business/nouns/action) it started, the [Events](/business/nouns/event) it emitted and the logs it wrote.

## Start from the request id
Every response carries a `Request-Id` header, and every problem document repeats it as `requestId`. The CLI prints it under any error, and the SDK puts it on every result and thrown error as `requestId`.

`shipwatch.dev` is a [Dataset API](/products/templates/dataset-api) of parcel tracking events, sold to online stores by the call. A store reports that switching to the higher plan fails on shipwatch's billing page. The developer copies one line from the failing response, `Request-Id: req_7Hk2`, and needs nothing else.

```bash
npx startup-builder show /requests/req_7Hk2
```

## The request log
The request log holds every request a namespace received, in `test` and `live`. It opens in startups.studio, for one [Startup](/business/nouns/startup) or across a whole [Portfolio](/business/nouns/portfolio). `show` prints the same record:

```json
{
  "$id": "https://api.sb/shipwatch.dev/requests/req_7Hk2",
  "at": "2026-10-22T14:03:11Z",
  "method": "POST",
  "path": "/subscriptions/subscription_12/switch",
  "status": 403,
  "key": "pk_live_…a91f",
  "durationMs": 38,
  "gates": [
    { "gate": "key", "verdict": "pass" },
    { "gate": "permission", "verdict": "fail", "rule": "Publishable keys run only public Verbs, and Subscription.switch is not public" }
  ],
  "action": null,
  "events": []
}
```

`gates` lists the checks in the order they ran, and the first `fail` is the answer. Here the billing page sends shipwatch's [publishable key](/code/api/guides/keys) from the browser, and that key runs only public [Verbs](/business/nouns/verb). The fix is to make the call from shipwatch's server, with a secret key, for the signed-in [Customer](/business/nouns/customer).

## Gates, in order
A call passes up to six gates before its [Verb](/business/nouns/verb) runs. Each verdict names the rule that decided it.

| Gate | It checks | A failure returns |
| --- | --- | --- |
| `key` | The key exists, is current and reaches this namespace | [`unauthorized`](/code/api/errors/unauthorized) |
| `input` | The input matches the Verb's schema | [`invalid-input`](/code/api/errors/invalid-input) |
| `permission` | The caller's [Permissions](/business/nouns/permission) cover this Verb | [`forbidden`](/code/api/errors/forbidden) |
| `rate` | The caller is under its request rate | [`rate-limited`](/code/api/errors/rate-limited) |
| `limit` | Spend and counts stay inside every [Limit](/business/nouns/limit) and [Mandate](/business/nouns/mandate) | An [Approval](/business/nouns/approval) wait, or [`limit-exceeded`](/code/api/errors/limit-exceeded) |
| `state` | The record's current state allows the Verb | A `refused` Action |

The first four reject at the door, so no Action exists. The last two create one, and the request log links to it.

## An Action that waits
A call that passed every gate but has not finished is a `pending` Action. Its `reason` says what it waits for, and the Action records every attempt:

```bash
npx startup-builder show /actions/action_31
```

`awaitingSource` means an outside service is down, and the platform retries it. `awaitingWorker` points at an open [Task](/business/nouns/task).

`awaitingTime` shows when its delay window closes. To give up, [cancel](/business/nouns/action/cancel) the Action; to run a `failed` one again, [retry](/business/nouns/action/retry) it.

## Traces
Send a W3C `traceparent` header, and the platform joins your trace instead of starting one. Every step under the call reports into it: [Workflows](/business/nouns/workflow), model calls, sandboxes and outbound requests.

A slow call then reads as one timeline in your own tracing tool. Code outside the platform sends spans over OTLP into the same trace. [Observability](/code/platform/observability) is the capability behind traces and logs.

## Logs
Code a Startup runs writes logs, tagged with the request id and the Action. Logs are kept forever.

```bash
npx startup-builder logs tail --request req_7Hk2
npx startup-builder logs tail --level error --follow
```

`--follow` keeps the stream open. An [Agent](/business/nouns/agent) that debugs reads the same request log, Actions and logs through MCP, with the same ids.

## Reproduce in test
To reproduce a failure safely, run the same call in `test` with the [Mode](/business/nouns/mode) `try`. It passes the same gates and stores nothing. The request log of a `try` call shows the verdicts exactly as a recorded call would.

## Next
- [Errors and testing](/code/sdk/guides/errors-and-testing): every error and how to force it in `test`.
- [Modes](/code/api/guides/modes): the reasons an Action waits, and what each one waits for.
- [Keys](/code/api/guides/keys): secret, publishable and session keys.