Troubleshooting

Shipmoor Team
August 5, 2026
9 min read

Common situations, what they look like, and what to do. Every message below is real shipmoor claim-check output. For the model this page assumes (the frozen acceptance set, the deterministic floor, and the judge), see What is Claim Check.

Authentication or allowance blocks Claim Check

Every installation must be authorized. Free includes five Claim Check invocations per month and requires the allowance service online before each admitted run:

shipmoor auth status
shipmoor usage

Authentication and allowance admission complete before the engine, judge, runner, or evidence work starts. Floor-only and full mode use the same Claim Check counter.

”unknown_signing_key” (from-source-build case)

$ shipmoor claim-check .
shipmoor: license verification failed: unknown_signing_key

This appears when you are running a from-source build of Shipmoor and the license signature cannot be verified against the bundled signing key set. It is a build-time configuration issue, not a Claim Check bug.

Fix: run shipmoor doctor to confirm the install is intact, and shipmoor capabilities --json to see the entitlement state. If you built from source, install the official binary instead:

curl -fsSL https://dl.shipmoor.dev/install.sh | SHIPMOOR_VERSION=0.10.0 bash
shipmoor login

“Why did my run come back INCONCLUSIVE even though nothing looked wrong?”

The most common cause has nothing to do with your change. When no acceptance set is committed, Claim Check can auto-derive one, and it writes that derived set as a draft, at .shipmoor/acceptance.yaml.draft, not as the live .shipmoor/acceptance.yaml. An unapproved draft downgrades an otherwise-READY run to INCONCLUSIVE: the obligations exist, but nobody has signed off that they’re the right obligations yet.

Fix: read the draft, and once you agree it states the right obligations, approve it by promoting it to the live acceptance set and committing it with the change:

mv .shipmoor/acceptance.yaml.draft .shipmoor/acceptance.yaml
git add .shipmoor/acceptance.yaml

A committed acceptance file is the approved, author-mode form. Until one exists, every run is checking your change against a draft nobody has agreed to, which is exactly what INCONCLUSIVE is for: not a failure, and not a silent pass either.

”the judge didn’t run”

You passed --agent and the judge opinion does not appear in the output. The most common causes, in order:

  1. The intent confidence is low. The judge only runs at medium or high confidence. Add a second, agreeing intent source (--intent-ticket alongside --intent-prompt) to raise it. See Providing intent.
  2. No cannot_check acceptance criteria. The judge only adjudicates acceptance criteria the floor marked cannot_check. If the floor decided every one, there is nothing for the judge to do.
  3. No agent is configured, or the bare preset name doesn’t resolve. Built-ins are claude, codex, and cursor. An unknown bare token fails fast with a usage error rather than silently skipping the judge (see the “agent command not found” section below), and with no --agent/review.agent at all, the judge simply abstains.
  4. --floor-only was passed. Floor-only mode skips the judge by design. Drop --floor-only to run full mode.

Diagnose with the trace sidecar:

shipmoor claim-check . --agent claude --trace-out .shipmoor/claim-check.trace.json

The trace carries, per acceptance criterion, why the judge did or did not run, and its rationale if it did.

”acceptance set malformed”

$ shipmoor claim-check .
shipmoor: acceptance set malformed: .shipmoor/acceptance.yaml: expected a top-level "acceptance_criteria" list, got mapping

Fix: the acceptance set must be a top-level list of acceptance criteria. Scaffold a known-good one with init and diff it against yours:

shipmoor claim-check init

The binary reads the acceptance set without a YAML dependency in the shipped artifact, so the parser is strict and the error messages are precise. Fix the structural issue the message names, then re-run.

”I wrote the test the fix packet asked for, but the obligation still isn’t satisfied”

When an acceptance criterion can’t be bound to an existing check, Claim Check prints a fix packet: a specific tag string it wants attached to a test. Two things trip people up here:

  • The match is an exact substring, not a fuzzy one. The tag string has to appear character for character somewhere in your test’s id or filename. A close paraphrase, a reworded test name, or the right idea captured only in a docstring does not bind. Copy the tag exactly as given.
  • The test has to actually distinguish base from head. The binder checks that your test fails at the base commit and passes at the head commit. A test that already passes before your change existed proves nothing about the change, and it will not bind to the obligation, even with the right tag attached.

Shipmoor is not the oracle here; your test is. Claim Check binds the obligation to that test, runs it at both commits, and records what happened. If the test doesn’t move from failing to passing across the change, there’s nothing to record a pass from. See Using Test Evidence with Claim Check for how a bound test’s result across commits becomes evidence Claim Check consumes.

”the judge agent preset has no built-in command”

$ shipmoor claim-check . --agent unconfigured
shipmoor: the judge agent preset 'unconfigured' has no built-in headless-JSON command for the intent-fidelity judge; pass a raw command instead, for example --agent "claude -p" (a print-mode CLI that answers a prompt with JSON).

This is exit 2 (a usage error: the judge never ran). Bare claude, codex, and cursor are supported. Any other single token is rejected rather than guessed at, because a wrong command would be worse than a clear failure.

Fix: use the claude, codex, or cursor preset, or point --agent at the raw command for whatever agent you want to drive (for example --agent "claude -p --model sonnet", or your own wrapper script), as long as it implements the wire contract. A raw command (anything with a space or a path in it) is never remapped, so it runs exactly as given.

A related but different error, shipmoor: judge agent not found: '…', means the resolved command itself couldn’t be launched: a typo, a binary not on PATH, or a script that isn’t chmod +x. Fix the command, not the preset name.

The judge “failed” (exit 3: the agent ran but the run failed)

$ shipmoor claim-check . --agent "my-agent"
Claim Check — failed
judge failed: all adjudications failed — check your LLM configuration and API key

Exit 3 is an operational failure (distinct from the exit-2 “not found” above): the judge launched but every adjudication failed. Common causes: the judge returned malformed JSON or an empty choices array, exited non-zero, wrote non-UTF-8 to stdout, or exceeded the timeout on every acceptance criterion. The ones the judge could not adjudicate stay cannot_check. The floor verdict is unaffected.

Can I run Claim Check in self-managed CI?

No. Current self-managed CI supports Scan only with a scan-scoped SHIPMOOR_TOKEN. Do not put interactive device credentials in CI or use a Scan token for Claim Check. See CI availability.

Large diffs and slow runs

A claim check runs per acceptance criterion with a worker pool. If runs are slow or time out:

  • Narrow the change: check a tighter selection (--staged, a smaller --from / --to range, or --diff <spec>) instead of the whole working tree or --all.
  • Run floor-only (--floor-only) to skip the judge entirely; this is the fastest local path.
  • If you run the judge, raise the per-acceptance-criterion timeout in your config (claim_check.timeout).

”Why didn’t the judge pass my change?”

By design. The judge is monotonic toward safety: it can only BLOCK by citing a divergence, or ABSTAIN by routing to a human. It never passes a judgment obligation. A READY verdict always comes from the deterministic floor, never from the judge. So a judgment acceptance criterion the floor routed to cannot_check either becomes BLOCKED (the judge cited a divergence, with a resolving pointer that mechanically resolves, and the sampling floor agreed), INCONCLUSIVE (the judge abstained on a required judgment), or stays open (the judge did not block).

If you want a local shell or script to react to the verdict, no extra flag is needed:

shipmoor claim-check . --floor-only   # exit follows the verdict

Choose floor-only or full mode deliberately rather than expecting the judge itself to hand you a passing verdict. See CLI reference.

Floor versus judge, at a glance

You want…Use
Adjudication of the judgment acceptance criteria the floor cannot checkshipmoor claim-check --agent <agent> (judge, monotonic toward safety)
A local deterministic exit on an unmet acceptance criterionshipmoor claim-check --floor-only
Both, with the judge’s BLOCK reflected in the exitshipmoor claim-check --agent <agent>

Diagnosing with shipmoor doctor and shipmoor capabilities

Two commands cover most diagnostics:

shipmoor doctor                # checks install and config integrity
shipmoor auth status           # account and device authorization
shipmoor usage                 # Claim Check allowance and renewal

shipmoor doctor walks the install and project configuration. Authorization and usage commands report the current account state without project context.

FAQ

Does Shipmoor send my code to a model or a server? The floor never calls a model. The judge, when you opt in, runs as your subprocess and may contact the provider you selected. Source, diffs, and repository content are not uploaded to Shipmoor by default. See Privacy & service contacts.

What happened to shipmoor scan --intent? It was folded into shipmoor claim-check and its documented subcommands. shipmoor scan is now the structural scanner with no --intent flag.

Can I run a claim check without an agent at all? Yes. Floor-only mode (no --agent, or --floor-only) runs the deterministic floor and synthesizer with no judge.

Is there a --fail-on flag on claim-check? No. --fail-on belongs to shipmoor scan. Claim Check doesn’t need an equivalent: its exit code already maps BLOCKED and INCONCLUSIVE to a non-zero code unconditionally. The two gates are independent; either can fail the build.

Where is the VSA written? To .shipmoor/claim-check.vsa.json by default, or to a path you choose with --vsa-out. Its predicateType is https://slsa.dev/verification_summary/v1. See Reading the verdict.

Last updated on August 5, 2026

Was this article helpful?

Your response is saved on this device.