# Troubleshooting

> Discovery diagnostics from eve info and eve build, .eve/discovery/diagnostics.json, common failure modes, dev server PID conflicts, and runtime error codes from failed steps/turns.

- Repository: vercel/eve
- GitHub: https://github.com/vercel/eve
- Human docs: https://grok-wiki.com/public/docs/vercel-eve-759e1d74a10f
- Complete Markdown: https://grok-wiki.com/public/docs/vercel-eve-759e1d74a10f/llms-full.txt

## Source Files

- `docs/guides/instrumentation.md`
- `docs/reference/cli.md`
- `packages/eve/src/cli/commands/info.ts`
- `packages/eve/src/compiler/artifacts.ts`
- `packages/eve/src/execution/runtime-errors.ts`
- `packages/eve/src/cli/dev/tui/setup-issues.ts`

---

---
title: "Troubleshooting"
description: "Discovery diagnostics from eve info and eve build, .eve/discovery/diagnostics.json, common failure modes, dev server PID conflicts, and runtime error codes from failed steps/turns."
---

Eve surfaces compile-time discovery problems through `eve info`, `eve build`, and `.eve/discovery/diagnostics.json`, and runtime failures through NDJSON stream events (`step.failed`, `turn.failed`, `session.failed`, or `session.waiting`). Start with discovery diagnostics before booting a dev server; for in-flight sessions, read the failure cascade and `code` field on the terminal boundary event.

## Discovery diagnostics workflow

Discovery runs on every compile. Eve writes artifacts under `.eve/` even when discovery produces errors, so you can inspect partial output after a failed build.

<Steps>
<Step title="Run eve info">

```bash
eve info
```

Or emit machine-readable output:

```bash
eve info --json
```

`eve info` reports compile status (`ready`, `failed`, or `unavailable`), error and warning counts, the active tools/skills/channels surface from the compiled manifest, messaging route paths, and artifact file paths.

</Step>
<Step title="Fix authored-shape errors">

Read each diagnostic's `message` and `sourcePath`. Errors block compile; warnings are printed at build time but do not fail the build.

</Step>
<Step title="Rebuild and verify">

```bash
eve build
```

When discovery errors remain, the CLI prints the full diagnostics report and the path to `.eve/discovery/diagnostics.json`. Re-run `eve info` to confirm `Compile: ready` and zero errors.

</Step>
</Steps>

<Note>
The recommended edit loop is: change files under `agent/` → `eve info` → `eve dev` → `eve build` → `eve start`. See the [CLI reference](/cli-reference) for command details.
</Note>

## Inspectable artifacts

Eve preserves discovery and compile artifacts under `.eve/`:

:::files
.eve/
├── discovery/
│   ├── agent-discovery-manifest.json   # what Eve found on disk
│   └── diagnostics.json                # authored-shape errors and warnings
└── compile/
    ├── compiled-agent-manifest.json    # serialized surface the runtime loads
    ├── compile-metadata.json           # build metadata, hashes, compile status
    └── module-map.mjs                  # compiled module entrypoints
:::

| Artifact | Path | Use when |
| --- | --- | --- |
| Discovery manifest | `.eve/discovery/agent-discovery-manifest.json` | Confirm a file was found on disk |
| Diagnostics | `.eve/discovery/diagnostics.json` | Read structured errors and warnings |
| Compiled manifest | `.eve/compile/compiled-agent-manifest.json` | See what the runtime actually serves |
| Compile metadata | `.eve/compile/compile-metadata.json` | Check `status` and diagnostic summary counts |
| Module map | `.eve/compile/module-map.mjs` | Trace compiled import entrypoints |

`eve info --json` includes an `artifacts` object with absolute paths to each file when compile state is available.

## diagnostics.json schema

Each diagnostics artifact is versioned and machine-readable:

<ResponseField name="kind" type="string">
Always `eve-discovery-diagnostics`.
</ResponseField>

<ResponseField name="version" type="number">
Schema version. Currently `1`.
</ResponseField>

<ResponseField name="summary" type="object">
`errors` and `warnings` counts. Build fails when `errors > 0`; `compile-metadata.json` records `status: "failed"` in that case.
</ResponseField>

<ResponseField name="diagnostics" type="array">
One entry per problem. Each diagnostic has:

- `code` — stable machine-readable identifier (for example `discover/required-instructions-missing`)
- `message` — human-readable explanation
- `severity` — `"error"` or `"warning"`
- `sourcePath` — absolute path to the offending file or directory
</ResponseField>

<ResponseExample>

```json
{
  "kind": "eve-discovery-diagnostics",
  "version": 1,
  "summary": { "errors": 1, "warnings": 0 },
  "diagnostics": [
    {
      "code": "discover/required-instructions-missing",
      "message": "No instructions prompt discovered.",
      "severity": "error",
      "sourcePath": "/path/to/agent"
    }
  ]
}
```

</ResponseExample>

When `eve build` fails, the CLI message includes the summary line, each diagnostic with severity and source path, and `Diagnostics artifact: <path>`.

Warnings are reported to stderr at build time:

```text
Warning [discover/deprecated-system-slot]: …
  source: /path/to/agent/system.md
```

## Discovery diagnostic codes

Diagnostic codes use the `discover/` prefix. The table below lists the stable codes emitted by the discovery compiler; the full set for your project is always in `.eve/discovery/diagnostics.json`.

| Code | Severity | Typical cause |
| --- | --- | --- |
| `discover/project-not-found` | error | No `agent/` directory resolved from the app root |
| `discover/required-instructions-missing` | error | Missing `instructions.md` or `instructions.ts` |
| `discover/deprecated-system-slot` | warning | Fallback to deprecated `system.{md,ts}` — rename to `instructions.*` |
| `discover/slot-collision` | error | Same slot has both markdown and module sources |
| `discover/module-slot-collision` | error | Multiple module sources compete for one slot |
| `discover/tool-name-invalid` | error | `agent/tools/<name>.ts` filename violates tool slug charset |
| `discover/connection-name-invalid` | error | Connection filename violates kebab-case slug rule |
| `discover/channel-name-invalid` | error | Channel filename or directory segment violates slug rule |
| `discover/hook-name-invalid` | error | Hook filename or directory segment violates slug rule |
| `discover/tools-directory-invalid` | error | `agent/tools/` exists but is not a directory |
| `discover/channels-directory-invalid` | error | `agent/channels/` exists but is not a directory |
| `discover/hooks-directory-invalid` | error | `agent/hooks/` exists but is not a directory |
| `discover/connections-directory-invalid` | error | `agent/connections/` exists but is not a directory |
| `discover/sandbox-directory-invalid` | error | `agent/sandbox/` exists but is not a directory |
| `discover/skills-directory-invalid` | error | `agent/skills/` exists but is not a directory |
| `discover/schedules-directory-invalid` | error | Root `schedules/` exists but is not a directory |
| `discover/unsupported-directory` | warning | Ignored directory under `agent/` |
| `discover/skill-collision` | error | Duplicate skill name |
| `discover/skill-markdown-missing` | error | Packaged skill directory missing `SKILL.md` |
| `discover/skill-frontmatter-invalid` | error | Invalid YAML frontmatter in a skill |
| `discover/connection-file-folder-collision` | error | Both file and folder exist for one connection name |
| `discover/connection-folder-empty` | error | Connection folder has no module source |
| `discover/sandbox-folder-empty` | error | Sandbox folder has no module source |
| `discover/required-subagent-config-module-missing` | error | Subagent missing required `agent.ts` |
| `discover/local-subagent-schedules-invalid` | error | Schedules under a subagent (root-only slot) |
| `discover/schedule-file-unsupported` | error | Unsupported file type under `schedules/` |

<Tip>
Tool names are derived from filenames under `agent/tools/` — there is no authored `name` field. If the model never sees a tool, confirm the file path and slug, then check diagnostics for shape errors. See [Project layout](/project-layout) and [Tools](/tools).
</Tip>

## Common failure modes

| Symptom | Likely cause and fix |
| --- | --- |
| Tool not discovered (model never sees it) | Run `eve info`. Confirm the file is in `agent/tools/<name>.ts` and default-exports `defineTool(...)`. Check `.eve/discovery/diagnostics.json`. Remember `schedules/` is root-only. |
| Model won't call a tool it should | Tighten the tool `description` and `inputSchema`; put procedural guidance in a skill, not the description. Confirm the tool appears in `eve info`. |
| Stuck on `session.waiting` | Turn is parked on approval, `input.requested`, or connection sign-in. Respond via the client, or POST a follow-up with the current `continuationToken`. A stale token is rejected. |
| `401` on production routes | Expected fail-closed auth. Replace `placeholderAuth()`, set `VERCEL_PROJECT_ID`, and configure environment so `vercelOidc()` accepts user tokens. See [Auth and deployment](/auth-and-deployment). |
| Build fails with discovery errors | Read the printed diagnostics and `.eve/discovery/diagnostics.json`. Validate root-vs-subagent boundaries and that secrets come from env vars, not authored files. |
| AI Gateway auth errors at runtime | Missing or stale `AI_GATEWAY_API_KEY` or `VERCEL_OIDC_TOKEN`. Run `eve link` or set credentials in `.env.local`. In `eve dev`, use `/model` to refresh. |
| `eve eval` exits `2` | Configuration error (missing evals, invalid flags, unreachable target). Exit `1` means a failed check or execution error; exit `0` means all passed. |

## Dev server PID conflicts

Local `eve dev` writes the active server process ID to `.eve/dev-process.pid`. Before starting, Eve checks whether that PID is still running.

<Warning>
If another `eve dev` is already running for the same agent, startup exits with:

```text
A dev server is already running for this Eve agent (pid 12345).
To stop it, run: kill 12345
```

On Windows the suggested command is `taskkill /PID <pid>`. The PID file is removed when the dev server shuts down cleanly.
</Warning>

### Port binding

When no explicit `--port` is given, Eve retries up to several consecutive ports if the default (`$PORT`, then `3000`) is in use (`EADDRINUSE`). With an explicit `--port`, a conflict throws immediately.

Manual cleanup after stopping `eve dev`:

- Delete stale runtime snapshots: `.eve/dev-runtime/snapshots/`
- Delete old local sandbox templates: `.eve/sandbox-cache/local/templates/`

Connect the TUI to a remote server instead of starting a local one:

```bash
eve dev https://your-app.vercel.app
# or
eve dev --url https://your-app.vercel.app
```

## TUI setup issues

The `eve dev` TUI runs cheap boot detections before the first prompt. Issues appear as an attention line (for example `1 setup issue: model provider not linked · /model`).

| Label | Fix command | When it fires |
| --- | --- | --- |
| `model provider not linked` | `/model` | No `.vercel/project.json` and no gateway credentials in env |
| `AI Gateway credentials missing` | `/model` | Project is linked but neither `AI_GATEWAY_API_KEY` nor `VERCEL_OIDC_TOKEN` is set |
| `not logged in` | `/login` | Off-critical-path `vercel whoami` probe reports logged out |
| `Vercel CLI not found` | `/vc` | `vercel` binary absent from `PATH` |

<Note>
External-provider models (routed outside the AI Gateway) skip gateway credential detections entirely — they use their own provider key and `/model` cannot reconfigure them.
</Note>

For gateway-auth `MODEL_CALL_FAILED` events, the TUI replaces generic remediation text with actionable lines (stale API key, expired OIDC token, or missing credentials).

## Runtime failure cascades

When a model call or turn fails, the harness emits a cascade of NDJSON events sharing the same `code` and `message`. The third event determines whether the session can continue.

```mermaid
stateDiagram-v2
  [*] --> TurnInProgress
  TurnInProgress --> TerminalFailure: emitFailedStep
  TurnInProgress --> RecoverableFailure: emitRecoverableFailedTurn
  TurnInProgress --> TurnComplete: success
  TerminalFailure --> SessionFailed: session.failed
  RecoverableFailure --> SessionWaiting: session.waiting
  TurnComplete --> SessionWaiting: conversation mode
  TurnComplete --> SessionCompleted: task mode
  SessionFailed --> [*]
  SessionWaiting --> TurnInProgress: follow-up with continuationToken
  SessionCompleted --> [*]
```

| Cascade | Events | Session state after |
| --- | --- | --- |
| Terminal | `step.failed` → `turn.failed` → `session.failed` | Dead — no further follow-up on the same continuation token |
| Recoverable | `step.failed` → `turn.failed` → `session.waiting` | Parked — send another message with the current `continuationToken` |
| Success (conversation) | `turn.completed` → `session.waiting` | Ready for next user message |
| Success (task) | `turn.completed` → `session.completed` | Terminal success |

`session.waiting` with `{ "wait": "next-user-message" }` is normal between turns. It also follows recoverable failures so you can retry after fixing credentials or transient provider errors.

Parked work that emits `session.waiting` without a failure cascade includes HITL approvals (`input.requested`), `ask_question`, and connection OAuth (`authorization.required`).

## Runtime error codes

Failure events carry `{ code, message, details? }`. The `code` is the stable identifier; `details` may include `errorId` (for log correlation), gateway metadata, or workflow-stream diagnostics.

### step.failed / turn.failed / session.failed codes

| Code | Terminal or recoverable | Meaning |
| --- | --- | --- |
| `MODEL_CALL_FAILED` | Both — terminal for config errors; recoverable for transient provider failures in conversation mode | Model call failed. Check `details` for `gatewayName`, `statusCode`, `errorId`. Gateway auth failures include `GatewayAuthenticationError` or summary name `AI Gateway authentication failed`. |
| `WORKFLOW_STREAM_WRITE_FAILED` | Recoverable | Durable event-stream flush to the workflow server failed (timeout, 5xx). `details` includes `operation`, `statusCode`, `url`, `vercelId`, `vercelError`. The model call may have succeeded. |
| `OUTPUT_SCHEMA_NOT_FULFILLED` | Terminal in task mode; recoverable in conversation mode | Agent could not produce output matching `outputSchema` / `final_output`. |
| `SESSION_FAILED` | Terminal | Session callback step failed. |
| `REMOTE_AGENT_START_FAILED` | Terminal | Remote agent dispatch could not start. |
| `REMOTE_AGENT_FAILED` | Terminal | Remote agent callback reported failure. |
| `SUBAGENT_EXECUTION_FAILED` | Surfaced on parent via `action.result` | Delegated subagent run failed; appears in subagent-result output, not always as a root-session `step.failed`. |

### Action and tool result codes

These appear on `action.result` events (and in tool-result message parts), not necessarily as `step.failed` codes:

| Code | Meaning |
| --- | --- |
| `TOOL_EXECUTION_DENIED` | HITL approval denied or tool execution blocked |
| `TOOL_EXECUTION_FAILED` | Tool returned an error-shaped JSON output (`{ code, message }`) |
| `ACTION_RESULT_FAILED` | Fallback when an action result is marked `isError` without a structured code |

### Continuation token errors

<ResponseField name="NO_ACTIVE_SESSION" type="runtime error code">
Thrown when `continuationToken` does not match an in-flight session. Callers using resume-or-start treat this as a signal to create a fresh session. Message: `No active session for continuationToken "<token>".`
</ResponseField>

### Failure event payload shape

<ResponseExample>

```json
{"type":"step.failed","data":{"code":"MODEL_CALL_FAILED","message":"AI Gateway rejected the OIDC token.","sequence":4,"stepIndex":1,"turnId":"turn_0","details":{"errorId":"err_abc","gatewayName":"GatewayAuthenticationError"}}}
{"type":"turn.failed","data":{"code":"MODEL_CALL_FAILED","message":"AI Gateway rejected the OIDC token.","sequence":4,"turnId":"turn_0","details":{"errorId":"err_abc","gatewayName":"GatewayAuthenticationError"}}}
{"type":"session.waiting","data":{"wait":"next-user-message"}}
```

</ResponseExample>

For terminal failures the cascade ends with `session.failed` instead of `session.waiting`. Clients should key on the boundary event and deduplicate the shared `code:message` pair across the cascade.

### Correlating with logs

Model-call and workflow-stream failures attach `errorId` in `details`. Grep server logs for that ID to find the structured dump. Unrecognized failures may also include `details.detail` with a full stack trace; recognized gateway and config failures omit the dump.

## Observability for runtime failures

Three surfaces help debug runtime issues:

| Surface | Where | What it shows |
| --- | --- | --- |
| NDJSON stream | `GET /eve/v1/session/:sessionId/stream` | Live `step.failed`, `turn.failed`, `session.failed`, tool events |
| Workflow run tags | Vercel Workflow dashboard (`$eve.*`) | Session/turn tree, model id, token counts — no `instrumentation.ts` required |
| OpenTelemetry | `agent/instrumentation.ts` | AI SDK spans when configured |

See [Instrumentation and evals](/instrumentation-and-evals) for tracing setup and workflow run tags.

## Related pages

<CardGroup>
<Card title="CLI reference" href="/cli-reference">
All `eve` commands, flags, exit codes, and the edit-info-dev-build-start loop.
</Card>
<Card title="Quickstart" href="/quickstart">
Scaffold, verify discovery with `eve info`, and iterate with `eve dev`.
</Card>
<Card title="Sessions and streaming" href="/sessions-and-streaming">
`continuationToken` contracts, NDJSON events, and reconnect behavior.
</Card>
<Card title="HTTP API" href="/http-api">
Stable `/eve/v1` routes and stream event vocabulary.
</Card>
<Card title="Auth and deployment" href="/auth-and-deployment">
Route auth, env vars, and production verification.
</Card>
<Card title="Project layout" href="/project-layout">
Authored slots, path-derived naming, and what compiles into `.eve/`.
</Card>
</CardGroup>
