Errors
Lantfly uses HTTP status codes to say whether a request worked, and every refusal from /api/v3 has the same body:
Error shape
{
"error": {
"code": "validation_failed",
"message": "The input field must be an object.",
"fields": { "input": ["The input field must be an object."] },
"details": {}
}
}
| Field | Always present | Description |
|---|---|---|
code | Yes | Stable snake_case identifier. Branch on it. |
message | Yes | Human-readable text in the request's language (Accept-Language: en or vi). Show it to people; don't parse it. |
fields | With validation_failed | Object of field name to a list of messages. Nested fields use dot paths, for example options.memory_mb. |
details | Sometimes | Extra facts about the refusal, for example details.permission or details.current. |
tip
New codes may appear over time. Handle the codes you care about, and fall back on the HTTP status for the rest.
Handling errors
Branch on error.code
const res = await fetch('https://lantfly.com/api/v3/actors/lantfly~tiktok-scraper/runs', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LANTFLY_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ input: { hashtags: ['skincare'], resultsPerPage: 30 } }),
});
if (!res.ok) {
const { error } = await res.json();
switch (error.code) {
case 'validation_failed':
console.error('Fix the input:', error.fields);
break;
case 'concurrent_runs_limit_exceeded':
// Wait for a run to finish, then try again.
break;
case 'not_enough_usage_to_run_paid_actor':
console.error('Buy credit or upgrade the plan.');
break;
default:
throw new Error(`${res.status} ${error.code}: ${error.message}`);
}
}
Codes by status
400 Bad Request
| Code | Meaning | What to do |
|---|---|---|
bad_request | The request is malformed. | Check the method, path and body. |
invalid_parameter | A query parameter has a value the endpoint can't use, such as an unknown dataset view. | Fix the parameter. |
invalid_input | The body can't be stored, for example a dataset item that isn't an object or a list. | Send valid JSON of the right shape. |
invalid_key | A key-value store key has characters outside a-zA-Z0-9!-_.'() or is over 256 characters. | Rename the key. |
idempotency_key_invalid | Idempotency-Key isn't 8 to 128 printable ASCII characters. | Use a UUID. See Idempotency. |
actor_standby_not_enabled | The actor's version doesn't have Standby on. | Turn Standby on for the version. See Actor Standby. |
actor_is_deprecated | The actor is deprecated and can't be used for Standby. | Pick another actor. |
401 Unauthorized
| Code | Meaning | What to do |
|---|---|---|
unauthenticated | No token, or the token is unknown, expired or revoked. | Send Authorization: Bearer … with a valid token. See Authentication. |
token_not_provided | A private storage was read without a token or signature. | Send a token, or use the storage's signed link. |
On the MCP server, a 401 also carries a WWW-Authenticate header that starts OAuth.
402 Payment Required
| Code | Meaning | What to do |
|---|---|---|
not_enough_usage_to_run_paid_actor | The plan's included usage and credit are spent. | Buy credit or upgrade the plan under Billing. |
billing_on_hold | The account is on hold and can't start runs. | Contact support. |
payment_required | A payment is needed for this action. | Check Billing. |
403 Forbidden
| Code | Meaning | What to do |
|---|---|---|
insufficient_permissions | The token's scope doesn't allow this: read-only token on a write, actor-limited token outside its actors, missing token permission, a run token outside its run, or an AI-app token used outside MCP. | Use a token with the right scope. The message names the missing permission. |
permission_denied | Your role in the organization doesn't allow this. details.permission names the permission. | Ask an owner or admin for a role that has it. |
forbidden | You may not access this resource, for example you aren't a member of the account in X-Lantfly-Account. | Check the account. A response with X-Lantfly-Account-Revoked: 1 means the membership is gone. See Organizations. |
session_required | Token and session management only works from the Console, not with an API token. | Do it in the Console. |
reauth_required | A sensitive change needs a recent password confirmation. | Confirm your password in the Console and try again. |
email_not_verified | Runs wait until the account's email address is verified. | Open the link Lantfly emailed you, or resend it from the Console. |
invalid_signature | A signed link's signature is wrong or expired. | Get a fresh link from the storage. See Signed links. |
404 Not Found
| Code | Meaning | What to do |
|---|---|---|
not_found | The resource doesn't exist, or you can't see it. | Check the ID and the account you act for. |
record_not_found | The actor or key-value record doesn't exist, or you can't see it. | Check the ID or key. |
Lantfly answers 404, not 403, for resources of other accounts, so IDs don't leak.
405, 409, 410
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 405 | method_not_allowed | The path exists but not with this method. | Check the method in the API reference. |
| 409 | conflict | The resource changed or is in a state that doesn't allow this (for example a listening project that isn't active). | Read the resource again and retry if it still makes sense. |
| 409 | run_finished | A charge or status update was sent for a run that has finished. | Nothing to retry. |
| 409 | billed_to_agency | This client workspace's billing is managed by its agency. | Ask the agency. |
| 409 | idempotency_key_reused, command_in_progress, command_outcome_unknown, idempotency_response_withheld, idempotency_response_too_large | An Idempotency-Key retry couldn't be replayed. | See Idempotency. |
| 410 | api_version_removed | The path belongs to a removed API version. | Call the path under details.current. See Versioning. |
| 410 | gone | The resource existed but is gone. | Don't retry. |
413, 422, 423
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 413 | payload_too_large | The body is over the endpoint's limit (for example a key-value record over 100 MB). | Send less. |
| 413 | request_too_large | The body is too large for a Standby actor. | Send less, or store the data first and pass a reference. |
| 422 | validation_failed | One or more fields are invalid. fields lists them. | Fix each field and resend. |
| 422 | unprocessable | The request is well formed but can't be done. | Read message. |
| 422 | nothing_to_collect | A listening source has nothing left to collect with its settings. | Change the source's settings. |
| 423 | account_suspended | The workspace is suspended: it can be viewed but not changed, and nothing new starts. | Contact the account's owner or agency. |
429 Too Many Requests
| Code | Meaning | What to do |
|---|---|---|
rate_limited | Too many requests in the time window. | Wait for Retry-After seconds. See Rate limits. |
concurrent_runs_limit_exceeded | The account already has as many runs waiting or running as its plan allows. | Wait for a run to finish, or upgrade the plan. |
daily_runs_limit_exceeded | The plan's runs per 24 hours are used. | Wait, or upgrade the plan. |
rate_limit_exceeded | Too many requests of the account are waiting at once on Standby or MCP. | Retry after Retry-After seconds. |
5xx
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 500 | server_error | Something failed on Lantfly's side. | Retry with backoff, with the same Idempotency-Key for writes. Contact support if it persists. |
| 502 | bad_gateway, standby_run_failed, standby_proxy_unreachable, response_too_large | An upstream (a Standby run) failed or answered with too much. | Retry; for response_too_large, make the actor answer with less. |
| 503 | unavailable, standby_capacity_exceeded | Temporarily unavailable, or the Standby run is busy. | Retry after Retry-After. |
| 503 | charge_busy | A charge couldn't take its lock in time. Nothing was charged. | Send the same request with the same Idempotency-Key after Retry-After (1 second). The Actor SDK does this for you. |
| 504 | standby_run_not_ready | The Standby run didn't become ready in time. It keeps starting. | Retry after Retry-After. |
Errors in MCP tool results
The MCP server reports most failures inside the tool result with isError: true and a text message,
not as HTTP errors. See MCP troubleshooting.