# Troubleshooting

One entry for each failure you can meet. The quote is the message text, or the
text that yaag matches on. An entry is at most ten lines, blank lines apart.

## Bun is missing

<!-- quote: src/process/status.ts -->

> yaag needs Bun and could not find it on PATH or in ~/.bun/bin.

Cause: the extension bridges to the Bun CLI, and Bun is not on `PATH` and not
in `~/.bun/bin`.

Fix: install Bun with `curl -fsSL https://bun.sh/install | bash`, then restart
pi. The extension resolves Bun once, at load.

## No API key for a spawned Agent

<!-- quote: @yaag/runtime/src/model/model-failure.ts -->

> No API key

pi says `No API key found for the selected model.`, or `No API key for
<provider>/<id>`. yaag reads that text and calls the failure `auth`.

Cause: a spawned Agent is hermetic, so it loads no pi extension of the session.
A model that a provider extension registers is out of reach.

Fix: name the provider extension in the `extensions` spawn option, or give the
Agent a model the machine can reach. A `model` list falls back on `auth`.

## failed to publish cassette

<!-- quote: @yaag/runtime/src/cassette/cassette-publish.ts -->

> failed to publish cassette

Cause: yaag could not write the Cassette. The destination is not writable, or
something else occupies the name.

Fix: give a writable path, then run again. A completed Run keeps its result and
reports the loss on `run_end.checkpointLost`. A stopped Run fails, because it
is not restorable.

## cannot create the Cassette directory

<!-- quote: @yaag/runtime/src/cassette/run-identity.ts -->

> cannot create the Cassette directory

Cause: yaag makes a missing directory of the `--record` path, and this one
could not be made. A name on the path is a file, or a parent refuses a write.

Fix: give a `--record` path yaag can make. The Run stops at the start, before
the first Agent, so no work is lost.

## Replay or resume mismatch

<!-- quote: @yaag/runtime/src/cassette/replay-divergence.ts -->

> replay diverged for agent

<!-- quote: @yaag/runtime/src/cassette/resume-identity.ts -->

> recorded profile

Cause: the program changed since the recording. A spawn option, an Agent
Definition field, or an Ask prompt no longer hashes to the recorded value. A
changed Profile does the same, because it changes what a Role binds.

Fix: restore the program to the recorded shape, or record again. A resume
replays only the Asks that still match, and runs the rest live.

## --resume or --replay needs the program

<!-- quote: @yaag/cli/src/argv.ts -->

> needs the program too: give <program.ts>, --eval <source>, or --eval-fd <n>.

Cause: a Cassette holds the history of a Run. It never holds the program.

Fix: name the program as well: `yaag run program.ts --resume run.json`.

## Inline program limits

<!-- quote: src/record/run-program-param.ts -->

> yaag_run: script is too large

Cause: an inline program (`script`, or `--eval`) must be 65536 bytes (64 KiB)
or smaller, and it can import `@yaag/runtime` and `typebox` only.

Fix: write the program to a file and pass `file` or `<program.ts>`. A file may
import any module.

## An Ask failed with a limit or a timeout

<!-- quote: @yaag/runtime/src/error-factories.ts -->

> limit reached at

Cause: `ASK_LIMIT` is a tripped soft budget (`maxTurns`, `maxToolCalls`,
`maxDurationMs`). `ASK_TIMEOUT` is `timeoutMs`, and it kills the Agent.
`ASK_INVALID_OUTPUT` is a result that never satisfied `outputSchema`.
`ASK_STALLED` is silence past the watchdog budget.

Fix: raise the budget, or add a `wrapUpPrompt`. After `ASK_LIMIT` the Handle is
alive, so the program can ask again.

## A fork or a compaction was refused

Cause: `COMPACT_DURING_ASK` and `FORK_DURING_ASK` mean an Ask of that Agent was
still in flight. Both operations need a settled Ask boundary. `FORK_REFUSED`
means the Agent cannot be forked at all: it was killed during an Ask, so the
end of its session is undefined, or it holds no session file, as a
Cassette-playback Agent does, or the Run holds no host session copy to fork from. `COMPACT_FAILED` means pi refused the summary.

`FORK_REFUSED` also means a `fork` spawn option that is not the Run's
`ctx.host`, and `OPTIONS_CONFLICT` means `compact` with no `fork`.

Fix: await the Ask before you fork or compact. For `FORK_REFUSED`, fork an
Agent that settled its last Ask, spawn a fresh Agent, or pass `ctx.host`.

## A Run continued after the session was replaced

<!-- quote: src/view/run-foreground.ts -->

> continues in the background: the session was replaced.

Cause: `/reload`, `/new`, `/resume`, `/fork` or an exit replaced the pi
session while a `yaag_run` was live. The old session cannot report to the new
one, so a blocking call ends with this error, and a background Run sends no
completion message. The Run itself keeps executing.

Fix: nothing is broken. The new session sees the Run as an orphan. Read its
verdict with `yaag_status({ id })`, or end it with `yaag_stop({ id })`.

## A pause was refused

<!-- quote: src/tool/pause-tool.ts -->

> Pause failed:

<!-- quote: src/tool/pause-tool.ts -->

> No Run with id

<!-- quote: src/tool/pause-tool.ts -->

> already ended.

Cause: the Control Channel refused the request or did not answer. Among the
codes are `BUSY`, `RUN_ENDED`, `RUN_SETTLING`, `CONNECT_FAILED`,
`CHANNEL_CLOSED`, and `FLUSH_BUDGET`. Fix: read the Run with `yaag_status`.
`yaag_stop` is still available, and the Run record is unchanged.

## A Reattach was refused

<!-- quote: src/view/run-reattach.ts -->

> was already resumed by

<!-- quote: src/view/run-reattach.ts -->

> Checkpoint path of run_end differs from the Run record. Refused.

Cause: one Checkpoint resumes one time, which the `resumedBy` field of the
record states. A `run_end` that names another Checkpoint means the record is
not the history of that Run.

Fix: open the successor Run in `/yaag`, or start a fresh Run with `yaag_run`.

## describe executes the module top level

<!-- quote: @yaag/cli/src/argv.ts -->

> describe imports the module and executes its top level.

Cause: `yaag describe` imports the program to read its declaration.

Fix: keep the module top level side-effect free. Put every action inside `run`.
A Catalog Resolve — `await $yaag.<scope>.importAgent(name)` — is the one
permitted top-level `await`: describe is meant to run it.
`describe --export <name>` imports the module too.

## Missing @yaag/runtime editor types

The editor says it cannot find the module `@yaag/runtime` in a program file.

Cause: the folder is not a Program Directory yet, so `.yaag/types/` is absent.

Fix: run the `yaag_setup_workspace` tool, or `yaag setup-workspace .`. It
reports the written declarations:

<!-- quote: @yaag/cli/src/setup-workspace.ts -->

> .yaag/types/: written

Rerun it after an upgrade to refresh the declarations.

## A config file is missing or invalid

<!-- quote: @yaag/runtime/src/config/config-file.ts -->

> does not exist

Cause: yaag reads the global config, the project config, and the `--config`
file at the start of a Run. A `--config` file that is not there, or any config
file that yaag cannot read or parse, stops the Run at the start (exit 1).

Fix: correct the path or the file. Give `--no-config` to ignore the global
config and the project config. [Configuration](configuration.md#locations)
names the three locations and the supported fields.

Plain usage errors of the CLI exit with code 2 and print the usage text. See
[the CLI reference](cli.md#usage).

## $yaag: no agent entry has this name

<!-- quote: @yaag/runtime/src/catalog/resolve.ts -->

> no agent entry has this name in

Cause: `CATALOG_ENTRY_NOT_FOUND`: the Registry File the message names has no
`agents` entry with that name, or the file does not exist.

Fix: add the entry to that Registry File, or correct the name in the program.

## $yaag: two agent entries have this name

<!-- quote: @yaag/runtime/src/catalog/resolve.ts -->

> agent entries have this name in

Cause: `CATALOG_ENTRY_AMBIGUOUS`: two or more `agents` entries in that Registry
File have the same name. The message prints each entry's `file`.

Fix: remove one entry, or give each entry a different name.

## $yaag: the entry did not resolve

<!-- quote: @yaag/runtime/src/catalog/resolve.ts -->

> did not resolve:

Cause: `CATALOG_ENTRY_UNRESOLVABLE`: the entry was found, but its target file is
absent, the module threw on import, the export is absent, or the export is not
an Agent Definition and not a Profiled Definition.

Fix: correct `file` or `exportName` in the Registry File, or export a Definition
from that module. `error.cause` holds the reason.

## A Profiled Definition could not be spawned

<!-- quote: @yaag/runtime/src/agent/spawn-profiled.ts -->

> this program declares no Profiles

<!-- quote: @yaag/runtime/src/profile/profile-view.ts -->

> is not declared by this program

Cause: `PROFILE_REQUIRED`: the program declares no Profiles. `ROLE_NOT_FOUND`:
the factory read an undeclared Role, even when it caught the throw.
`PROFILE_NOT_FOUND` names a Profile the program does not declare, and the origin
of the id: your command line, a config file, or the Cassette a resume continues.

Fix: declare the Profiles and the Role, or read a declared Role name
([Authoring](authoring.md)).

## A system prompt holds a render marker

<!-- quote: @yaag/runtime/src/system-prompt/prompt-guards.ts -->

> Render Sentinels are expanded inside a defineSystemPrompt definition only

<!-- quote: @yaag/runtime/src/system-prompt/prompt-guards.ts -->

> holds an unknown render marker

Cause: `yaagSystemPrompt()` and each `ctx.render*()` call write a marker, and
yaag expands a marker inside a `defineSystemPrompt` definition only. A marker in
a plain `systemPrompt` string, or a marker name yaag does not know, stops the
spawn with `SPAWN_FAILED` before the Agent starts.

Fix: wrap the text in `defineSystemPrompt(...)`, and write no marker by hand
([Authoring](authoring.md)).

## A user-input spawn was refused

<!-- quote: @yaag/runtime/src/agent/ask-user-capability.ts -->

> and disallowedTools denies it

<!-- quote: @yaag/runtime/src/agent/ask-user-capability.ts -->

> and the tools allowlist omits it

Cause: `canAskUser` needs the tool `request_user_input`, and the tool flags of
the same spawn remove it. Fix: add the tool to `tools`, or remove it from
`disallowedTools`.

## A recorded user-input protocol differs

<!-- quote: @yaag/runtime/src/cassette/resume-preconditions.ts -->

> this yaag ships protocol

Cause: the Cassette recorded another version of the user-input tool, so the
resume is refused. Fix: record the Run again with this yaag.

## An answer was refused

<!-- quote: @yaag/runtime/src/run/answers.ts -->

> names no open question of this checkpoint

<!-- quote: @yaag/runtime/src/run/answers.ts -->

> it cannot be answered with

Cause: the answer key is not an open question of this Checkpoint, or the
question already holds a different answer. Fix: read `questions` and
`resume.answersTemplate` of the paused document, and use those keys. Sending
the same answer again is safe.

## A resume could not restore an Agent question

<!-- quote: @yaag/runtime/src/cassette/session-answer.ts -->

> it is not the session this checkpoint recorded

<!-- quote: @yaag/runtime/src/cassette/session-answer.ts -->

> cannot read the session file

Cause: the Agent's session file moved, changed, or was deleted after the
Checkpoint was written. Fix: record the Run again. The answer is appended
before any process starts, so nothing was consumed.

## HOST_SESSION_UNUSABLE

<!-- quote: src/tool/run-tool.ts -->

> HOST_SESSION_UNUSABLE: this pi session has no session file

Cause: `yaag_run({ forkHost: true })` ran in an ephemeral pi session. Such a
session has no session file, so it has no conversation to fork. No Run started.
Fix: call `yaag_run` again without `forkHost`.
