Which type of error each code becomes
PHPThe type of error each SDK raises for an error code of the API, how the types are related, and the errors the SDKs raise themselves.
Each SDK raises one type of error for each error code of the API, and the two SDKs agree: a code is the same type in PHP and in Node.js. This page names the type of each code, and the errors the SDKs raise without an answer of the API.
How the types are related
Every error of the SDK has one root type:
SlenExceptionin PHP, in the namespaceSlen\Sdk\Exceptions, andSlenErrorin Node.js. Acatchof the root takes every error the SDK raises.A type is named the same way in both languages:
BudgetExceededExceptionin PHP isBudgetExceededErrorin Node.js.The refusals of a spend have a parent of their own,
SpendRefusedExceptionin PHP andSpendRefusedErrorin Node.js. Every answer with the status402is raised as this type or as a type that extends it.A blocked customer,
CustomerBlockedExceptionorCustomerBlockedError, extends the type of a policy refusal,PolicyDeniedExceptionorPolicyDeniedError.Every other type extends the root directly.
A code the SDK has no type for is raised by its status: as an error of the key for a
401or a403, as the refusal of a spend for a402, as the rate limit for a429, as an error of the provider for a5xx, and as a refused request for any other status.
The type of each code
The table leaves out the codes of the console and the settings: no call of the SDK makes the requests that answer them.
| Code | HTTP status | SDK error type | What it means | What to do |
|---|---|---|---|---|
invalid_api_key | 401 | AuthenticationException PHPAuthenticationError Node.js | The request carries no API key, or a key Slen does not know — copied wrong, revoked, or replaced by a rotation. | Check the value of the Authorization header. A key that was revoked does not work again; issue a new one in the console. |
insufficient_scope | 403 | AuthenticationException PHPAuthenticationError Node.js | The key is valid and lacks the scope the operation requires — or the role of the person signed in to the console does not include it. The message of the error names that scope, and speaks of an API key in both cases. | Use a key that has the scope, or issue one that has it. Give a key only the scopes its service needs. A person signed in to the console needs a role that includes the scope; an owner or an admin of the organization gives it. |
not_authenticated | 401 | AuthenticationException PHPAuthenticationError Node.js | Nobody is signed in. The request has no API key and no session of a person signed in to the console, or the session has ended. | Send an API key in the Authorization header, or sign in to the console again. |
not_a_member | 403 | AuthenticationException PHPAuthenticationError Node.js | The person signed in to the console is not a member of the organization the request is about, or does not belong to any organization yet. | Accept an invitation to the organization, or switch to an organization you are a member of. |
project_access_restricted | 403 | — | The caller reaches only some projects of the organization and tried to change something that belongs to the whole organization, or to read the audit log. An API key reaches only the project it belongs to. | With an API key, create the thing in the project of the key — a provider connection with its scope set to project. A person asks a member who reaches every project to make the change. |
account_suspended | 403 | AuthenticationException PHPAuthenticationError Node.js | The account of the person signing in is suspended, and the sign-in is refused. | The account cannot sign in until it is restored. Write to support to learn why. |
policy_denied | 403 | PolicyDeniedException PHPPolicyDeniedError Node.js | A policy refused the request before any money was held. The message of the error names the policy. | Read in the message which policy refused. Change the request — the model, the operation, the cost — or change the policy in the console. |
model_not_allowed | 403 | PolicyDeniedException PHPPolicyDeniedError Node.js | A model node of the flow names a model the catalogue does not have, or one that is switched off. The execution ends as failed with this code. | Choose a model from the list of models in the model node — the list holds the active models that have a price in effect — and publish a new version. |
budget_exceeded | 402 | BudgetExceededException PHPBudgetExceededError Node.js | The call would take a budget over its limit. What the budget already holds and has spent in its current window, together with the hold this call asks for, is more than the limit. | Wait for the next window of the budget — its resets_at says when; a budget of the type total does not start again. Or raise the limit of the budget. |
operation_limit_exceeded | 402 | OperationLimitExceededException PHPOperationLimitExceededError Node.js | A per-operation budget caps what one call of the operation may hold, and the hold this call asks for is above that cap. | Ask for less — fewer output tokens, a cheaper model — or raise the cap. The same request is refused again until one of them changes. |
concurrency_limit_exceeded | 402 | ConcurrencyLimitException PHPConcurrencyLimitError Node.js | A budget of the type concurrency — Concurrent holds in the console — allows a set number of holds to be open at the same time, and all of them are taken by calls that are running. | Send the request again once a running call has ended, or raise the limit of the budget. A request to a flow goes again under a new key, since its rejected execution keeps the key it had. This is not the rate limit of the key. |
insufficient_credits | 402 | InsufficientCreditsException PHPInsufficientCreditsError Node.js | The credit account of the customer cannot cover the price of the call in credits, or the customer has no account of that credit type. A charge or an adjustment is refused the same way when it would leave the balance below what the account holds. | Top up the credits of the customer. An account whose settings allow a negative balance does not refuse. |
customer_blocked | 403 | CustomerBlockedException PHPCustomerBlockedError Node.js | The end customer the run is made for is blocked. A new run of theirs is refused before anything is created. A run of theirs already under way is refused at its next hold of credits, and the execution ends with this code. | Unblock the customer to let their runs through again. While a customer is blocked, their credits can still be topped up, charged and adjusted, and their statement read. |
customer_has_history | 409 | — | The customer cannot be deleted, because something already happened to them — an account holds credits or a reservation, or the statement has an entry. The journal of credits is only added to, and its entries explain the balance. | Block the customer instead of deleting them. |
customer_not_found | 404 | CustomerNotFoundException PHPCustomerNotFoundError Node.js | The project does not know the customer the request names — the customer was never added, topped up or set up, or was deleted. A priced call for such a customer is refused this way, and so is a read, a block, a charge or a deletion. An adjustment of an account that does not exist is refused the same way. | Add the customer first, or top them up — a top-up creates the customer and the account. |
overrun_stopped | 402 | OverrunStoppedException PHPOverrunStoppedError Node.js | The estimate of a model call in a flow, made again after its hold was taken and before the provider is called, came out larger than the hold by more than the overrun tolerance of the node, and the overrun policy of the model node is to stop. The hold was given back, and the provider was not called. The same code ends the execution when a person refused the approval an overrun asked for, or nobody answered in time. A new model node has no overrun policy, and a policy that a node has practically never fires, because both estimates come from the same request a moment apart. | Send the request again under a new key — the call is estimated anew and takes a hold of its own. To stop such refusals, turn the overrun policy of the model node off and publish a new version. |
overrun_approval_required | 402 | OverrunApprovalRequiredException PHPOverrunApprovalRequiredError Node.js | The estimate of a model call in a flow, made again after its hold was taken and before the provider is called, came out larger than the hold by more than the overrun tolerance of the node, and the overrun policy of the model node asks a person to approve the difference. The execution waits for that decision, so the request is answered with the waiting execution, not with this code. A new model node has no overrun policy, and a policy that a node has practically never fires, because both estimates come from the same request a moment apart. | Decide on the approval in the console. An approval that is refused, or that nobody decides in time, ends the execution with overrun_stopped. |
reservation_not_found | 404 | — | Not an answer of any operation of the API. Slen keeps it for a hold it cannot find while it settles a model call. | Nothing to handle. Should an answer carry it, write to support and quote the id of the request. |
reservation_expired | 409 | — | Not an answer of any operation of the API. Slen keeps it for the extension of a hold that has expired; an expired hold still takes the capture of its call. | Nothing to handle. Should an answer carry it, write to support and quote the id of the request. |
invalid_request | 409, 422 | — | The request cannot be carried out as it stands, and the message of the error says why — a policy without the parameter its action needs, or with a condition its action never meets; selected projects for a member whose role reaches every project; an Idempotency-Key longer than 190 characters. The SDKs raise an error with this code themselves for a call they refuse before sending it. | Read the message and change the request. |
idempotency_key_required | 400 | — | The operation requires an Idempotency-Key header, and the request has none, or an empty one. | Send a key of your own that names the piece of work, and send the same key when you repeat that work. |
idempotency_conflict | 409 | IdempotencyConflictException PHPIdempotencyConflictError Node.js | The Idempotency-Key was used before by another request — the same key with another body, or the key of another top-up, charge or adjustment of the project. | Send the new request under a new key. A repeat of the first request under its key is answered as before. |
idempotency_in_progress | 409 | IdempotencyConflictException PHPIdempotencyConflictError Node.js | A model call of a flow met a hold that still stands under its own key, and was refused so that the provider is not called twice. The execution ends as failed with this code. An ordinary run never meets it. | Read the execution and its trace. Send the request again under a new key only if you still need the answer — the first call may have been paid for. |
cost_calculation_failed | 422 | InvalidRequestException PHPInvalidRequestError Node.js | The model is active and has no price in effect, so Slen cannot compute what the call would cost, and the call is refused. | Name a model from the list of models — it holds the active models that have a price in effect. |
provider_not_configured | 422 | ProviderException PHPProviderError Node.js | No connection of the project can serve the provider of the requested model, so there is nowhere to send the call. In a flow, the same code answers when the pool a model node routes the call through was deleted or is switched off. | Add a connection to that provider in the console, or enable the one you have. Switch the pool back on, or choose another pool in the model node and publish a new version. Then send the request under a new key. |
provider_rate_limit | 429 | ProviderException PHPProviderError Node.js | The provider answered that its rate limit was reached. A pool that switches connections on a rate limit tries another one first; this code reaches you when nothing else was tried. | Send the call again later under a new key. Add a connection to the pool, or let the pool switch connections on a rate limit. |
provider_error | 502 | ProviderException PHPProviderError Node.js | The provider refused the call or answered with something Slen cannot use, and the call did not complete. | Check what the request asks of the model — a parameter the model does not take is refused by the provider. Send the call again under a new key once the request is right. |
provider_timeout | 504 | ProviderException PHPProviderError Node.js | The provider could not be reached — the name did not resolve, or the connection failed — so the call never went out. Despite the name, it does not mean that the model was slow. | Send the call again later under a new key. A provider that was reached and did not answer in time is operation_uncertain, not this code. |
provider_unavailable | 502 | ProviderException PHPProviderError Node.js | The provider answered with a failure on its own side. Slen pauses that connection for a while, and a pool that switches connections tries another one. | Send the call again later under a new key. A pool with more than one connection rides out the outage of one of them. |
pool_exhausted | 503 | ProviderException PHPProviderError Node.js | No connection of the pool could serve the call within the attempts the pool allows. last_error_code in the details of the error names the last failure, and the Retry-After header says how long to wait when that is known. | Wait as long as Retry-After says, then send the call again under a new key. Add connections to the pool if it runs out often. |
operation_uncertain | 504 | OperationUncertainException PHPOperationUncertainError Node.js | The provider was called and its answer did not come back, so it is not known whether the call was made and paid for. A model call of a flow that ran in the background ends the same way when the provider accepted it and could no longer be asked about it. The hold is not given back; it stays until it expires. An execution that ends this way has the status uncertain. | Do not send the call again under a new key — that may be a second paid call. Read the operation or the execution to learn what it did. The webhook event operation.uncertain announces such a call as well. |
ledger_unavailable | 503 | ServiceUnavailableException PHPServiceUnavailableError Node.js | The spend ledger could not be reached when the call asked for its hold. The call was not authorized — nothing was held for it, and its provider was not called. | Send the request again later — a request to a flow under a new key, since its failed execution keeps the key it had. GET /v1/degraded-status says what the API lets through while the ledger is down. |
flow_runtime_error | — | FlowRuntimeException PHPFlowRuntimeError Node.js | The code the runtime keeps for a flow that broke while it was being walked, for a reason it has no narrower code for. No request is answered with it today, and no execution ends with it — a failure of a walk carries a narrower code, or none. | Nothing to handle today. Should an answer carry it, read the trace of the execution to see where it stopped. The model calls made before that were paid for, and a repeat under a new key pays for them again. |
invalid_flow_input | 422 | — | The input does not carry what a node of the flow needs — a flow that calls a model needs a non-empty messages in its input. The execution is closed as failed, and the key stays with it. | Fix the input and send it under a new key. A repeat under the same key is answered with the failed execution. |
step_limit_exceeded | 500 | FlowRuntimeException PHPFlowRuntimeError Node.js | The walk did not reach a terminal node within the number of steps one walk is allowed. The flow is larger than the runtime walks in one request. | Make the flow shorter, or split the work between two operations. Then send the request under a new key — a repeat under the same key is answered with the failed execution. |
unrouted_port | 500 | FlowRuntimeException PHPFlowRuntimeError Node.js | A node left through a port that nothing is connected to, and the walk had nowhere to go. The message of the error names the node and the port. | Connect that port in the flow builder and publish a new version. Then send the request under a new key — a repeat under the same key is answered with the failed execution. |
execution_timeout | 504 | TimeoutException PHPTimeoutError Node.js | The walk of the flow ran out of the time one walk is given. A model call that had answered before that was paid for. | Read the trace of the execution to see where the time went. Before you repeat the request, mind that a repeat under a new key pays again for what was paid. |
execution_parked | — | — | Not an answer of the API. Inside the runtime it marks a walk that stopped to wait, and the request is answered with the execution, waiting or queued. | Nothing to handle as an error. Wait for the execution as for any other that waits. |
http_request_failed | 502 | FlowRuntimeException PHPFlowRuntimeError Node.js | A call the flow makes to another HTTP API failed or was answered with an error, and nothing is connected to the error port of the node that made it. It is not a model provider. That node is frozen unless the service is set up otherwise — a version already published with it runs, and a new version cannot hold it. | Check the API the flow calls, then send the request under a new key — a repeat under the same key is answered with the failed execution. The error port of a frozen node cannot be connected in a new version — to change what the flow does on this error, publish a version without the node. |
rate_limit_exceeded | 429 | RateLimitException PHPRateLimitError Node.js | The API key, or the person signed in to the console, sent more requests in a minute than the limit allows. A few operations have a smaller limit of their own, such as the check of a provider connection. The Retry-After header of the answer says how many seconds to wait. Reading the status of an execution counts too. | Wait as long as Retry-After says, then send the request again. Nothing was held or spent for the refused request. |
flow_not_found | 404 | — | No flow answers the operation code — no flow is bound to it, the flow has no published version, or the flow is archived. Nothing is created, so the idempotency key stays free. The same code answers the id of a flow the caller does not reach. | Bind the operation code to a flow and publish the flow. A repeat under the same key runs once the flow can answer. |
operation_not_found | 404 | — | No operation — the record of one model call with its provider attempts — has this id in the project of the key. | Check the id. An operation of another project answers the same way. |
invalid_credentials | 401, 502 | — | Two cases. A sign-in to the console whose email and password do not match an account. A model call whose provider refused the key of the connection that served it — Slen then marks the credentials of that connection as invalid. | Sign in with the right password. For a connection, put a valid provider key into it in the console. |
csrf_token_mismatch | 419 | — | A request of a session of the console came without its CSRF token, or with one that is stale. A request with an API key never gets this code. | Reload the page of the console and do it again. |
service_unavailable | 503 | ServiceUnavailableException PHPServiceUnavailableError Node.js | Slen could not reach its database and answered before doing anything. The same code answers a change of a budget that waited too long for the calls running on that budget; nothing was changed. | Send the request again later. A refused change of a budget says in Retry-After when. |
not_found | 404 | — | The sign-up and the sign-in of the console answered as if the address did not exist. They are open only to a browser that has opened the access link it was given. | Open your access link in this browser, then sign up or sign in again. |
background_hold_expired | — | TimeoutException PHPTimeoutError Node.js | Not an answer of the API — it ends an execution started in async mode. A model call of the flow ran in the background at the provider, and its hold was settled by another capture while it waited, so the call ended without asking the provider for its answer. Nothing was given back, and the provider may still bill the call it accepted. Despite the name, a hold that has only expired does not end a call this way. | Send the request again under a new key only if you still need the answer. The provider may bill the first call as well, so the answer may be paid for twice. |
execution_conflict | 500 | FlowRuntimeException PHPFlowRuntimeError Node.js | The execution could not be opened — its record collided with another one, and not on the idempotency key. The flow did not run. | Send the request again. If it happens again, write to support and quote the id of the request. |
unknown_node | 500 | FlowRuntimeException PHPFlowRuntimeError Node.js | The published version of the flow leads to a node the runtime cannot find, so the walk stopped. | Publish the flow again from the flow builder, then send the request under a new key — a repeat under the same key is answered with the failed execution. If a new key meets the error again, write to support and quote the id of the request. |
node_type_not_supported | 500 | FlowRuntimeException PHPFlowRuntimeError Node.js | The published version of the flow has a node of a type the runtime cannot run. | Replace the node in the flow builder and publish a new version. Then send the request under a new key — a repeat under the same key is answered with the failed execution. |
flow_execution_not_found | 404 | — | No execution with this id exists in the projects the caller reaches — it never did, or it belongs to another project. | Check the id. It is execution_id of the answer that started the execution. |
A code with no type of its own is raised as the type of the HTTP status of the answer:
401,403AuthenticationExceptionPHP,AuthenticationErrorNode.js402SpendRefusedExceptionPHP,SpendRefusedErrorNode.js429RateLimitExceptionPHP,RateLimitErrorNode.js- 500 and above
ProviderExceptionPHP,ProviderErrorNode.js - any other status
InvalidRequestExceptionPHP,InvalidRequestErrorNode.js
Errors the SDKs raise themselves
Some errors come without an answer of the API, or before a request is sent.
| Type | When |
|---|---|
ConnectionException, ConnectionError | Slen could not be reached, or the connection broke before the answer was read |
TimeoutException, TimeoutError | No answer came within the timeout of the SDK — timeout and connectTimeout of SlenConfig, timeoutMs in Node.js — or within the timeout of the call |
InvalidRequestException, InvalidRequestError | The SDK refuses a call before sending it: an empty idempotency key, an empty external user id, an amount of credits that is not a decimal string, a context that names another customer, a timeout or a number of repeats of the call out of range. The code is invalid_request |
InvalidResponseException, InvalidResponseError | The API answered with a 2xx and a body that cannot be read; the error keeps the status. A webhook delivery whose signature holds and whose body is not an event raises the same type |
WebhookSignatureException, WebhookSignatureError | The signature of a webhook delivery does not hold — Webhooks |
A connection error and a timeout have neither a code nor a status. Every other error of this table has a code: a code of the SDK's own, which the API never answers with — except invalid_request, which the API uses too.
The SDKs' own codes, and the type of error each SDK raises for each:
| Code | PHP | Node.js |
|---|---|---|
invalid_request | InvalidRequestException | InvalidRequestError |
invalid_response | InvalidResponseException | InvalidResponseError |
webhook_signature_invalid | WebhookSignatureException | WebhookSignatureError |
webhook_payload_invalid | InvalidResponseException | InvalidResponseError |
After a connection error or a timeout it is not known whether Slen did the work. After an unreadable answer it is not known either: the call may have gone through.
A setting the SDK cannot be built with — an empty key, a timeout that is not above zero — is InvalidArgumentException, raised where the SDK is built. It is a mistake in the code, not an error of the SDK, and it does not extend SlenException.
Where to go next
Handling errors — catch the errors by type, and tell by the type whether a run cost money.
When spend is refused — the family of a refused spend and its two forms.
Error codes — what each code means and what to do about it.
Built from openapi b070e1f, sdk contract 6a2e0e0, php 4089db3, node 0fa87be