---
title: Job refusals
description: What happens when a job:<id> run or a fallback route can't pick or reach a provider, the result.code values, and the route.skipped codes behind them.
---

Send `endpointId: "job:<job id>"` to [`run`](/mcp-tools/run) (REST, MCP or `looot run`) in place of a specific
endpoint id, and looot picks the first provider of that job, in `prefer` order, that can run now
and accepts your input. See [Jobs](/concepts/jobs) and [Fallback](/concepts/fallback). When no
provider can be picked or reached, the run fails with `error.code: "validation_error"` and a
`result.code` naming the specific reason, one of the five below.

### unknown_job

`result.code: "unknown_job"`. The `job:<id>` you sent isn't a job looot knows, and no endpoint is
filed under it either. The message suggests up to 3 close job ids. Retryable: no. Fix: use a
suggested id, or take the `job.id`/`capability` value from a search row ([`search_catalog`](/mcp-tools/search-catalog),
`GET /v1/catalog/search`, `looot search`). Don't guess the id. See [`search`](/mcp-tools/search).

### no_supply_for_job

`result.code: "no_supply_for_job"`. The job exists in looot's vocabulary, but no endpoint in the
catalog does it. The same code appears as a warning on `search_catalog` and [`discover`](/mcp-tools/discover) with empty
results, before you ever try to run it. Retryable: no. Fix: search again in other words, pick a
different job, or ask for it with the `capability_request` tool. See [`capability_request`](/mcp-tools/capability-request).

### needs_input

`result.code: "needs_input"`. Every provider of the job was reachable, but none of their input
schemas accepted the input you sent. `result.needs` lists each provider id and the field names it
needs. Retryable: no. Fix: add one of the named fields (the search answer's `jobInputs` names the
same fields with descriptions) and send a new [`idempotencyKey`](/concepts/idempotency). See [Job inputs](/concepts/job-inputs).

### no_runnable_provider

`result.code: "no_runnable_provider"`. The job exists and its providers' schemas would accept the
input, but none of them can run for this workspace right now (no usable credential, drained, or
unpriced). Retryable: no. Fix: connect a key for one of the listed providers, or pick another job. See [Bring your own provider key](/guides/bring-your-own-key).

### invalid_input

`result.code: "invalid_input"`. A value in a shared input field is malformed before it ever
reaches a provider: an `email` with no `@`, a `url` with no `http://`/`https://`, a `domain` that
isn't a bare domain name, or a `phone` with under 7 digits. Charged $0. Retryable: no. Fix: correct
the value and send a new `idempotencyKey`; the same key replays the same refusal. See [Job inputs](/concepts/job-inputs).

## When fallback runs but calls nothing

A run with `fallback` set can also fail with `route_capped` or `route_no_fit` on its `error`
object (these are documented in [Run errors](/errors/run-errors), since they apply to any
fallback route, a `job:` run or not). Both mean no provider was ever called, so the run charges
$0.

### route_capped

Every candidate's price was above `fallback.maxCostUsd`. Retryable: no. Fix: raise
`fallback.maxCostUsd`, or change the input; `route.skipped` says why each provider was skipped. See [Cost cap](/money/cost-cap).

### route_no_fit

Nothing ran for any other reason (bad input, short balance, missing credential, a route policy).
Retryable: no. Fix: when every skip is one you can change (see `route.skipped` below), change the
input and retry; otherwise no provider for this job can run for this request right now, so try
another endpoint or report it. See [Fallback](/concepts/fallback).

## route.skipped codes

`route.skipped[]` (on a fallback run) and the `skipped` list a `job:` run's `requestedJob` object
carries name why each candidate that was not run got passed over: `{endpointId, providerId, code,
reason}`.

| Code | Meaning |
| --- | --- |
| `excluded` | Named in `fallback.exclude`. |
| `unavailable` | Cannot run for this workspace now (disabled, drained, no usable credential). |
| `unpriced` | No price is published for it. |
| `not_idempotent` | The endpoint may change something, so fallback never tries it automatically. |
| `blocked_by_policy` | The workspace's route policy refuses this candidate. |
| `input_invalid` | Your input doesn't fit this provider's schema. |
| `needs_identity` | This provider needs a field the input doesn't have (the field is named in `reason`). |
| `no_credential` | No usable credential for this provider. |
| `over_cost_cap` | This candidate's price is above `fallback.maxCostUsd`. |
| [`insufficient_balance`](/errors/rest-errors#insufficient_balance) | The workspace balance can't cover this candidate's price. |
| `not_on_this_path` | Left out on a synchronous fixture run; a live gateway call would try it. |
| `max_attempts` | `fallback.maxAttempts` was already reached. |
| `fallback_disabled` | Fallback was turned off after the run was queued. |
| `error_bound` | The route already hit its limit of 2 error-class attempts. |
| `provider_already_tried` | This provider already had one attempt earlier in the same route. |
| `stopped` | The walk already stopped (a hit, a weak hit, or `stopAtFirstMiss` after a miss). |

`excluded`, `input_invalid`, `needs_identity`, `over_cost_cap` and `insufficient_balance` are
things you can change on the next request. The rest describe a candidate that could never have run
on this route.

<Related />
