Skip to content

Common Errors

An issue keeps a stale lock: it still has shipper:locked, but no active Shipper run appears to be working on it.

Shipper uses shipper:locked to prevent two agents from advancing the same issue at the same time. The lock can outlive the run that created it if a process exits unexpectedly, or if the configured lockTimeoutMinutes window has not elapsed yet.

Use shipper unlock <issue> when you know no run is still active. Use shipper unlock --stale to clear only locks that are older than the configured lockTimeoutMinutes value.

shipper next, shipper ship, or the desktop app cannot tell which stage an issue is in because the issue has no workflow label or more than one workflow label.

Every Shipper issue must have exactly one workflow label such as shipper:new, shipper:implemented, or shipper:ready. Missing labels usually mean the repository was not initialized or the issue was not adopted. Duplicate labels usually mean labels were edited outside Shipper.

Run shipper init if the repository has not been initialized or if the workflow labels need to be synced. Use shipper adopt <issue-or-pr> for a single existing issue or PR, or shipper adopt --all for existing GitHub issues that should enter the Shipper workflow. --all remains issue-only. PR adoption rejects closed or merged PRs, draft PRs, fork PRs, already-tracked PRs, and PRs with ambiguous closing references with actionable messages. Desktop users can perform equivalent label-state recovery through the app without duplicating the CLI steps here.

Shipper cannot read issues, update labels, create pull requests, or clone GitHub-backed worktrees because GitHub API or git authentication fails.

Interactive runs need an authenticated GitHub CLI session. Containers and CI usually rely on Auth tokens, and git operations also need a usable credential helper.

For local interactive use, run gh auth login and confirm gh auth status passes. In noninteractive environments, export one of the supported Auth tokens in the same environment that runs Shipper.

Worktree Creation and Install Command Failures

Section titled “Worktree Creation and Install Command Failures”

A stage fails while creating its isolated worktree, preparing dependencies, or running the configured dependency bootstrap.

Shipper creates ephemeral worktrees under ~/.shipper/worktrees/. Dependency bootstrap consists of the optional installCommand followed by executable .shipper/hooks/worktree-setup. Non-zero install or setup-hook exits warn and continue so an agent can still inspect and repair the worktree. Timeouts still abort bootstrap when installCommand or worktree-setup exceeds hookTimeoutMinutes.

When neither installCommand nor executable .shipper/hooks/worktree-setup is configured, Shipper prints a visible advisory warning and continues without installing dependencies. An empty installCommand means setup deliberately recorded that no bootstrap is needed.

Check that the repository can create git worktrees, that the failing worktree path under ~/.shipper/worktrees/ is writable, and that the configured bootstrap is valid for the repository. For multi-package repositories, verify both installCommand and .shipper/hooks/worktree-setup cover the package/project areas needed by the first build or test. If the bootstrap is legitimate but slow, raise hookTimeoutMinutes for the repository.

A stage stops before the agent runs with a message like Branch "shipper/42-add-feature" is already checked out at /path/to/checkout.

Git allows a local branch to be checked out in only one checkout or worktree at a time. Shipper needs to create a stage worktree on that branch, so it cannot continue while another local location is holding the branch.

Switch the named checkout to a different branch and rerun the stage. If the named path is a separate worktree, removing that worktree is also valid. Shipper will not switch, remove, detach, or otherwise alter that holder for you.

Shipper warns or refuses to run because the repository’s recorded cliVersion does not match the CLI that is running now.

shipper init records the Shipper CLI version in .shipper/settings.json. If the installed CLI is newer only within the same major version, Shipper allows the command with a warning. Missing or unreadable fingerprints, installed CLI downgrades, and major-version drift are blocked because the repository may have been initialized against incompatible or newer Shipper behavior.

Rerun shipper init from the repository root to refresh Shipper-managed files and the recorded cliVersion. This also clears repeated same-major warnings by refreshing the fingerprint. Use the SHIPPER_SKIP_VERSION_CHECK runtime override only as a temporary escape hatch when you must run before refreshing the repository configuration.

A stage stops with an agent timeout, or a hook, worktree setup, teardown, or install phase times out before it finishes.

Headless agent processes are bounded by agentTimeoutMinutes. File-based hooks and the worktree dependency install command are bounded by hookTimeoutMinutes.

Raise agentTimeoutMinutes for stages that need more agent runtime, or set it to 0 to disable the agent timeout. Raise hookTimeoutMinutes when hooks or install steps are expected to run longer, or set it to 0 to disable hook timeout enforcement.

An issue is marked shipper:failed, repeatedly rolls back after reject verdicts, or stops after too many transitions.

Shipper treats reject as a rollback event, not an immediate command failure. It can keep advancing after rollback until the work reaches a terminal point, but the shared transition cap MAX_TRANSITIONS = 15 prevents infinite loops and marks the issue shipper:failed when exhausted.

Use shipper reset <issue> to reset a failed issue to an earlier valid stage, or shipper reset --to <stage> <issue> to choose the target explicitly. Blocked issue recovery starts with shipper unblock. Desktop users can perform equivalent label-state recovery through the app.

An agent does not see expected Shipper MCP tools, or a run loads tools when the stage should avoid MCP access.

MCP loading is controlled by commands.<stage>.disableMcp, stage defaults, local settings, and per-run flags. The effective policy can differ between stages.

Set commands.<stage>.disableMcp for persistent stage policy. For one run, use --disable-mcp to prevent MCP loading or --enable-mcp to force loading when a stage default disables it.

Automation needs to distinguish a normal shipper ship failure from pause, retriable failure, or an interrupted PR remediation poll.

shipper ship has dedicated exit codes for pause and retriable failure. Interrupted check polling is documented on shipper pr remediate, not as a current shipper ship exit code.

Handle 75 from shipper ship as the pause sentinel and 76 as a retriable failure. Handle 130 as interrupted shipper pr remediate check polling. Current shipper ship maps ordinary stage failures to 1.