Errors and status codes
Every error the Qualflare API returns: the JSON error body, each HTTP status and code with its message, the request_id for support, and when to retry.
Last updated
When a Qualflare API request fails, the API answers with an HTTP status from 400 to 503 and a JSON body whose code field names the error, such as auth.unauthorized for a missing or expired token.
Error body
The error body is a JSON object with a code, and a message, request_id and fields when they apply:
{
"code": "common.validation_failed",
"message": "some fields are invalid",
"request_id": "3f0c2a5e-8b1d-4c6e-9a7f-2d4b6e8c1a90",
"fields": [{ "field": "name", "rule": "required", "message": "name is required" }]
}| Field | What it holds |
|---|---|
code | The error, always sent. Match on it in your code |
message | Text for people. Sent for 4xx and plan errors, never for 5xx |
request_id | The X-Request-Id of the response |
fields | Validation errors only: a field, rule and message for each field |
The request_id is the value to quote to support.
Status codes
| Status | Codes | Retry |
|---|---|---|
400 | common.validation_failed, common.invalid_input, environment.not_found, milestone.not_found, common.resource_not_found | No: fix the request |
401 | auth.unauthorized | No: fix the token |
402 | quota.exceeded, billing.subscription_inactive, billing.feature_unavailable | No |
403 | authz.project_access, authz.forbidden | No |
404 | <resource>.not_found, common.resource_not_found | No |
405 | common.method_not_allowed | No |
409 | common.conflict | No |
413 | common.invalid_input | No: make the body smaller |
415 | common.invalid_input | No: send JSON |
429 | common.rate_limited | Yes, after a pause |
500 | common.unknown, common.service_error | Yes |
503 | common.service_error | Yes |
400 Bad Request
common.validation_failedwithsome fields are invalid, and onefieldsitem per field, such asname is required,name must be at most 255 charactersorstatus must be one of: ….common.invalid_inputwithContent-Type must be application/json,Idempotency-Key must be at most 255 charactersorinvalid sort parameter.- On an upload:
environment.not_foundwithenvironment "<uid>" does not exist in this project,milestone.not_foundwithmilestone #<n> does not exist in this project, orcommon.resource_not_foundwithlanguage "<uid>" is not supported. These are400, not404, so a wrong environment name never looks like a wrong URL.
401 Unauthorized
No token gives access token is required; a wrong, revoked or expired token gives invalid or expired access token. The response carries WWW-Authenticate: Bearer realm="qualflare", with error="invalid_token" added when a token was sent. See Why a token stops working.
402 Payment Required
A plan limit stopped the request: quota.exceeded with a message such as Launches quota exceeded (<used>/<limit>), billing.subscription_inactive with subscription is inactive or expired, or billing.feature_unavailable with feature '<key>' is not available on your plan. See What happens at a limit.
403 Forbidden
authz.project_accesswithno project access: the token's creator no longer has the role the request needs.authz.forbiddenwithproject is not accessible: the token's project was deleted. A suspended project or workspace givesauthz.forbiddenwith the reason.authz.forbiddenwiththis access token is read-only: it can read and upload test results, but changing cases, steps, defects or suites needs a token created with "Allow writes": a write other than an upload used a token created without Allow writes.
404 Not Found
A record that doesn't exist gives <resource>.not_found, such as suite.not_found with suite not found (also case, launch, defect, test_plan and milestone), or common.resource_not_found for a cluster or a step. A path the API doesn't have gives common.resource_not_found with Not Found.
405, 409, 413 and 415
405withcommon.method_not_allowed: the path doesn't take that method.409withcommon.conflictandresource already exists(with the index name in parentheses when known) orreferenced resource constraint violated: the record clashes with one that exists, or refers to one that doesn't.413withcommon.invalid_inputandRequest Entity Too Large: the body is over its limit (Rate limits and request sizes).415withcommon.invalid_inputandrequest body must be application/json: the body is in another format.
429 Too Many Requests
Too many requests from one IP address get {"code":"common.rate_limited"}, with no Retry-After header. On /mcp, a token over its own limit gets the message too many requests, please try again later and Retry-After: 1. See Limits.
500 and 503
Neither carries a message, only code and request_id. A 500 is common.unknown, or common.service_error for a database constraint violation. A 503 with common.service_error means the token check was busy, so retry. A database outage during the token check is a 500, not a 401, so a client retries instead of treating the token as revoked.
Retry failed requests
- Retry
429,500,502,503and504with a growing pause.qfdoes this itself, 3 times by default, with pauses from 1 to 30 seconds (Retry & timeout). - Send an
Idempotency-Keyheader onPOST /api/v1/collectandPOST /api/v1/collect/ctrfso a retried upload can't create a second launch. See Retry safely with Idempotency-Key. Other writes take no key: retrying a create that succeeded makes a second record. qfturns statuses into exit codes: see Exit codes.
Related
- Reference: Rate limits and request sizes · Access Tokens · MCP server errors
- CLI/API: Troubleshoot qf and CI uploads · Qualflare API
Public reports and badges
Embed the badge, banner and social images of a published Qualflare report, and read its launches as JSON with no token: every URL, state and cache time.
Rate limits and request sizes
Qualflare API rate limits and request sizes: requests per second per IP address and per MCP token, the 1 MB and 10 MB body limits, upload caps and quotas.