Errors

Every /v1/ API error uses one envelope and one stable code value.

Envelope shape

{
  "error": {
    "type": "invalid_request_error",
    "code": "unknown_filter",
    "message": "'resistence' is not a filterable field on a motor. Filterable fields: current_max (or iq_max), kv, poles (or n), resistance (or R), weight.",
    "param": "resistence[lte]",
    "request_id": "req_2c5tQ...",
    "doc_url": "https://thrustlab.com/docs/guides/errors#unknown_filter"
  }
}
Envelope shape
FieldNotes
typeThe coarse taxonomic class for the error.
codeThe stable machine-readable string for the specific failure.
messageHuman-readable explanation. message may be reworded, so never branch on it.
paramThe request field that caused the error when present. null otherwise.
request_idThe req_<ksuid> correlator to quote in a support ticket.
doc_urlA link to the specific code row: https://thrustlab.com/docs/guides/errors#<code>.

Some codes carry extra fields as siblings of the canonical ones. credits_insufficient carries required_amount and available_balance. spec_rate_limited carries retry_after_s, budget_per_hour, budget_per_day, remaining_hour, remaining_day. create_rate_limited carries retry_after_s, limit_per_minute, kind. solver_no_convergence carries error.details with nonconverged_rows, observed_rows, fraction, and limit.

Error types

Error types
TypeHTTP statusRetryable?When
invalid_request_error400 / 422NoMalformed input, validation failure, unknown enum value, or (422) a semantic precondition failure on an otherwise well-formed request.
authentication_error401NoMissing, malformed, or invalid credential.
permission_error403NoAuthenticated but not authorized for this resource.
not_found_error404NoResource does not exist or is not visible to the caller.
conflict_error409No (without input change)Request conflicts with current resource state.
idempotency_error409No (without a new key or matching body)Idempotency-Key reused with a different request body.
rate_limit_error429Yes (after Retry-After)The flat per-credential request bucket, the per-account submission limit, the free-tier catalog filter budget, or the distinct-component datasheet budget.
insufficient_credits_error402No (until balance changes)Compute action requires more compute units than available.
api_error500 / 503YesServer-side fault. The two expected 503 variants are billing_not_configured and read_only_maintenance.

Every 429 response includes a Retry-After header in seconds. The four 429 codes are rate_limit_exceeded, create_rate_limited, filter_rate_limited, and spec_rate_limited. See rate limits for what each budget counts.

Four codes never appear as HTTP statuses: solver_no_convergence, solver_failure, propeller_geometry_missing, and sweep_points_persist_failed. Those are in the error object on a RUN RESOURCE whose status is "failed". Fetching that run returns HTTP 200 with the failure inside it. A client polling a run reads status first, then error.

Code catalog

Each row is generated from the server's own code registry, and each row id is the anchor an error's doc_url points at.

invalid_request_error (400 / 422)

invalid_request_error error codes
CodeHTTPRetryableWhat it means
VALIDATION_ERROR422NoA well-formed request violates a domain rule; the message names it.
airfoil_fit_failed422NoThe uploaded coordinates could not be fitted to a usable section.
already_dispatched400NoThat run was already handed to a worker and cannot be dispatched again.
dat_too_large400NoThe uploaded airfoil coordinate file is above the size limit.
dynamic_limit_exceeded422NoRotors times save steps exceeds the plan's dynamic ceiling.
events_required400NoA webhook endpoint must subscribe to at least one event type.
geometry_not_loftable422NoThe blade sections cannot be lofted into a solid.
idempotency_key_required400NoEvery write request needs an Idempotency-Key header.
idempotency_key_too_long400NoThe Idempotency-Key header is longer than 255 characters.
invalid_analysis_request400NoThe geometry analysis request is missing or contradicts a required field.
invalid_component_axis400NoA sweep component axis targets an out-of-range rotor slot or mixes component types.
invalid_component_id400NoA component id is malformed or names a component of the wrong type.
invalid_created_at400NoA `created_at` filter is not a valid timestamp.
invalid_cursor400NoThe pagination cursor is malformed, or was issued for a different sort than the one requested.
invalid_dat400NoThe uploaded airfoil coordinate file could not be parsed.
invalid_email400NoThe supplied email address is not a valid address.
invalid_filter_bounds400NoOn the free tier, catalog range filters must land on the published preset bounds.
invalid_filter_value400NoA range-filter value is not a finite number.
invalid_geometry422NoA propeller geometry is outside the bounds the solver accepts.
invalid_limit400NoThe `limit` parameter is outside the accepted range.
invalid_pack_component422NoA battery in the pack topology is missing a required cell property.
invalid_project400NoThe project id is malformed or names no project this account owns.
invalid_request400NoA query parameter or body field is outside its accepted range or vocabulary.
invalid_rotation400NoA propeller rotation label is outside the accepted vocabulary.
invalid_schedule422NoThe dynamic control schedule is incomplete or inconsistent.
invalid_status400NoThe run is not in a status this action accepts.
invalid_status_filter400NoThe `status` filter is not one of the published run statuses.
invalid_sweep_config400NoThe sweep axes do not form a valid grid; the message names the failing axis.
pack_cell_limit_exceeded422NoThe pack topology holds more cells than the engine supports.
pack_too_large_for_dynamic422NoThe pack is above the cell ceiling for a transient run; use a steady-state run or a smaller pack.
parallel_voltage_mismatch422NoPacks wired in parallel must have the same series cell count.
request_body_too_large400NoThe request body exceeds the maximum size accepted for an idempotent request.
request_validation_failed400NoThe request body or query string failed schema validation; `param` names the offending field.
rotor_limit_exceeded422NoThe run has more rotors than the plan allows.
simulation_not_exportable422NoThis run's shape is not supported by the requested export format.
sweep_limit_exceeded422NoRotors times points exceeds the plan's sweep ceiling.
sweep_too_large400NoThe sweep grid exceeds the 10,000-point ceiling for one submission.
sweep_too_small400NoA sweep must define at least two evaluation points.
unknown_airfoil422NoAn airfoil reference names no airfoil this account can use.
unknown_event_type400NoA subscribed event type is not one the API emits.
unknown_filter400NoA bracket filter names a field this component type does not have; the message lists the fields it does have.
webhook_url_dns_failure400YesThe webhook hostname did not resolve at the time of the request.
webhook_url_invalid400NoThe webhook URL has no hostname.
webhook_url_not_https400NoA webhook URL must use https.
webhook_url_not_publicly_routable400NoThe webhook hostname resolves to a private or reserved address.

authentication_error (401)

authentication_error error codes
CodeHTTPRetryableWhat it means
UNAUTHORIZED401NoThe credential was rejected on a first-party endpoint.
invalid_api_key401NoThe API key is unknown, revoked, or belongs to a disabled account.
invalid_jwt401NoThe bearer token is malformed, expired, or not an access token.
invalid_jwt_subject401NoThe token is valid but its subject is not an active user.
missing_authorization401NoThe request carried no Authorization header.

permission_error (403)

permission_error error codes
CodeHTTPRetryableWhat it means
FORBIDDEN403NoThe caller may not act on this resource.
challenge_failed403NoThe verification challenge token was not accepted.
challenge_required403NoReading a catalog datasheet from a browser session needs a verification challenge; API-key callers never see this.
email_unverified403NoThe account must verify its email address before running a simulation.
permission_denied403NoThe caller may not modify this resource.
pro_required403NoMulti-pack battery topology is a Pro feature.

not_found_error (404)

not_found_error error codes
CodeHTTPRetryableWhat it means
NOT_FOUND404NoThe referenced record does not exist or is not visible to this account.
airfoil_not_found404NoNo airfoil with that id is visible to this account.
component_not_found404NoNo component with that id is visible to this account.
credit_transaction_not_found404NoNo credit transaction with that id exists.
event_not_found404NoNo event with that id belongs to this account.
export_expired404YesThe export download link has expired; request the export again.
geometry_style_not_found404NoNo geometry style with that id exists.
not_found404NoNo published resource matches that identifier.
project_not_found404NoNo project with that id belongs to this account.
resource_missing404NoNo run with that id belongs to this account.
starred_component_not_found404NoThat component is not starred in this project.
submission_not_found404NoNo component submission with that id exists.
user_not_found404NoThe authenticated user record could not be loaded.
webhook_delivery_not_found404NoNo webhook delivery with that id belongs to this account.
webhook_endpoint_not_found404NoNo webhook endpoint with that id belongs to this account.

conflict_error (409)

conflict_error error codes
CodeHTTPRetryableWhat it means
CONFLICT409NoThe resource is not in a state that allows this action.
active_simulation409NoThe simulation is queued or running; cancel it before deleting.
active_sweep409NoThe sweep is queued or running; cancel it before deleting.
already_running409NoThe run is already executing.
already_starred409NoThe component is already starred in this project.
already_terminal409NoThe run has already finished, failed, or been canceled.
component_in_use409NoThe component is referenced by saved simulations; delete those first.
delivery_not_terminal409NoThe webhook delivery is still in flight; wait for it to settle before replaying.
export_in_progress409YesAn export of this run is already building; poll instead of starting another.
export_not_ready409YesThe export is still building; poll the run until it is ready.
idempotency_request_in_progress409YesA request with this Idempotency-Key is still being processed; retry shortly to receive its result.
project_has_active_runs409NoThe project has runs that are still queued or running; cancel or wait for them before deleting it.
submission_already_reviewed409NoThe submission has already been accepted or rejected.

idempotency_error (409)

idempotency_error error codes
CodeHTTPRetryableWhat it means
idempotency_key_reused_with_different_body409NoThe Idempotency-Key was already used with a different request body.

rate_limit_error (429)

rate_limit_error error codes
CodeHTTPRetryableWhat it means
create_rate_limited429YesThe account submitted more runs of this kind in one minute than the submission limit allows; the response carries the limit and the wait.
filter_rate_limited429YesThe free tier's filtered catalog-query budget for this hour is spent.
rate_limit_exceeded429YesThe per-credential request bucket is empty; wait for `Retry-After` seconds.
spec_rate_limited429YesThe account has read datasheets for its budget of distinct components; the response carries the remaining budget and the reset.
too_many_streams429YesThis account has too many open live streams; close some before opening another.

insufficient_credits_error (402)

insufficient_credits_error error codes
CodeHTTPRetryableWhat it means
INSUFFICIENT_CREDITS402NoThe account does not hold enough credits for this run.
credits_insufficient402NoThe account does not hold enough credits for this run.
upgrade_required402NoThe action needs a higher plan; the response names the gate and the cheapest plan that grants it.

api_error (503 / in the run resource)

api_error error codes
CodeHTTPRetryableWhat it means
billing_not_configured503YesBilling is not configured on this server.
propeller_geometry_missingin the run resourceNoThe propeller spec does not describe a blade the solver can build.
read_only_maintenance503YesNew runs are paused for maintenance; reads and drafts still work.
solver_failurein the run resourceNoThe run failed for a reason with no more specific code; the details stay in the server logs.
solver_no_convergencein the run resourceNoToo many points of the run did not converge for the results to be physical, so the run was rejected and the credits refunded.
sweep_points_persist_failedin the run resourceNoThe sweep solved but its point rows could not be stored, so the results are incomplete.

Reading errors in client code

The recommended pattern across every official SDK:

  1. Branch on type for the high-level class of failure (auth vs validation vs not-found vs rate-limit).
  2. Branch on code only when the user-visible path differs within that type.
  3. Treat the code set as open, and fall back to the type handler for unknown codes.
  4. Always log request_id.
  5. On 429, wait the number of seconds in Retry-After. Do not use a fixed backoff.

For rate-limit and idempotency rules, see stability policy. For the 402 insufficient-balance envelope, see compute units, and for rate budgets, see rate limits.