HTTP Error Codes
These are the HTTP answers the Werk24 API gives when it refuses a request: a submit to /techread/read-with-callback, and the calls the Python client makes for you. Problems inside a read that was accepted (an unreadable page, an unsupported ask) arrive as exceptions on the messages of that read instead; see Error Handling.
Error Response Format
A refusal from the API carries a JSON body with the status as a string in code and a human-readable message. details and request_id are there when they apply, and left out when they do not:
code: the HTTP status, as a string.message: what went wrong, for a human. Do not parse it.details: more about the refusal. Where there is a machine-readable reason it is indetails.error, for exampleQUOTA_EXHAUSTEDorPRIORITY_TOO_HIGH. Branch on that, not on the message.request_id: quote it to support. Present once the request got that far.
A request refused before it reaches Werk24 (by the gateway in front of the API, for example because it is too large) has no body of this shape.
Status Codes
| Status | When | Retry? | The Python client raises |
|---|---|---|---|
400 | The request is malformed: a missing or invalid field, a body that is not multipart, an Authorization header that is not two words (Token <key>), or an invalid priority. | No: fix the request. | BadRequestException; InvalidPriorityError for an invalid priority |
401 | No token, a scheme other than Token, or a key the API does not know. | No. | UnauthorizedException |
403 | priority above your account's tier (PRIORITY_TOO_HIGH). A key refused when the client opens its connection is also a 403. | No. | PriorityTooHighError; UnauthorizedException for a refused key |
| too large | The request is too large. It is refused before it reaches Werk24, with no body of ours and no request_id; the status depends on the gateway. | No: send a smaller request, or use read_drawing. | RequestTooLargeException (a 413); versions newer than 2.7.0 raise a subclass of it before sending |
415 | The drawing is not a supported file format. | No. | UnsupportedMediaType |
429 | The account's request allowance is used up (QUOTA_EXHAUSTED). | No. It does not reset with time. | InsufficientCreditsException from read_drawing_with_callback; see below for read_drawing |
5xx | A fault on our side. | Yes, after a pause. | RetryableServerError |
400 Bad Request
Examples of what the API sends:
details.error of "Invalid request data" is the validation message; it names the field that failed. Fix the request and send it again; the same request is refused the same way. A refused request is not charged.
401 Unauthorized
Without an Authorization header the message is "Authorization header missing". Check that the header is Authorization: Token <your-key>, that the key has no stray whitespace, and that it is still listed on the console's Keys page. With the Python client, check which key it found: see Get an API key.
403 Forbidden
Ask for your account's tier or a lower one. See Priority.
413 Request Too Large
A submit to /techread/read-with-callback carries the drawing in its own body, which is limited to about 4.6 MB. A larger request is refused before it reaches Werk24, so the answer has no body of ours and no request_id. See Drawing File Size Limit.
415 Unsupported Media Type
The body is the one under Error Response Format. Convert the drawing to PDF, PNG, JPEG or TIFF; see Supported File Formats.
429: request allowance used up
The only 429 the API sends means the account's request allowance is used up. It only happens on accounts that have such an allowance. It does not reset with time, and there is no Retry-After: retrying sends the same refusal. Contact your Werk24 account team to extend the allowance.
A 429 without this body, from the gateway in front of the API, would mean you are sending too fast: back off and retry.
In the Python client, read_drawing_with_callback raises InsufficientCreditsException for any 429, so do not retry it in a loop. read_drawing never sees a 429: a used-up allowance ends the read at its start, surfacing as a validation error or a ServerException. If every read_drawing fails that way, check the allowance before retrying.
5xx Server Errors
We are notified automatically. Retry after a pause. If it persists, contact support with the request_id. On the HTTP route, a 500 is rarely returned for a read that was queued anyway: if callbacks arrive for that request_id, do not submit it again. See the HTTP API page. The Python client does not pass on the request_id of a 5xx, so if a second read would matter, carry your own reference in the callback URL or a callback header and let your receiver drop a duplicate.
Python Client Exception Classes
The Python client turns a refusal into one of these exceptions, all subclasses of TechreadException and all importable from werk24:
| Exception | Status |
|---|---|
BadRequestException | 400 |
InvalidPriorityError | 400, invalid priority (has invalid_value) |
UnauthorizedException | 401 to 403, and a key refused at connect |
PriorityTooHighError | 403, PRIORITY_TOO_HIGH (has account_tier and requested_priority) |
ResourceNotFoundException | 404 |
RequestTooLargeException | 413, and (newer than 2.7.0) a callback request checked too large before sending |
UnsupportedMediaType | 415 |
InsufficientCreditsException | 429 on the HTTP calls, such as read_drawing_with_callback |
RetryableServerError | 5xx |
ServerException | any other unexpected status; also the base of InsufficientCreditsException and RetryableServerError |
InsufficientCreditsException is a ServerException, so catch it before ServerException, or a spent allowance ends up in your retry path:
RequestTooLargeException and the Callback Size Exceptions
A callback request carries the drawing inside its body, and that body is limited to about 4.6 MB, shared with the other form fields (see Drawing File Size Limit). From versions newer than 2.7.0, read_drawing_with_callback checks this limit before sending and raises one of two subclasses of RequestTooLargeException, so an existing except RequestTooLargeException keeps catching both. The example needs such a version; on 2.7.0 its import fails:
A stream that cannot seek (a pipe or a socket) cannot be measured in advance and is sent as is. Version 2.7.0 has neither exception and does not check the size: it sends the whole request, which is refused without a request_id, and the exception it then raises depends on how the gateway answers. So on 2.7.0, check the size yourself before sending, for example with os.path.getsize(path) > 4_600_000, and send larger drawings with read_drawing.
Best Practices
- Branch on the status and on
details.error, never onmessage. The message is for people and can change. - Retry only a
5xx, with a growing pause. Every4xxsends the same refusal again, and a429does not reset with time. - Log the
request_idof every refusal that carries one, and quote it to support. - Check the size before a callback submit: about 4.6 MB for the whole request.
Troubleshooting
"Invalid or expired authentication token" but the key looks correct
- Check the header is
Authorization: Token <your-key>, with theTokenprefix and no extra whitespace. - Check the key is still listed on the console's Keys page.
- With the Python client, check which key it found: any license file (
.werk24orwerk24_license.txt, in the current folder or your home folder) is read beforeW24TECHREAD_AUTH_TOKEN. See Get an API key.
429 on every request
- The account's request allowance is used up. It does not reset with time: contact your Werk24 account team.
A callback request fails and returns no request_id
- Check the drawing size: a callback request is limited to about 4.6 MB, including the other form fields (Drawing File Size Limit)
- Submit larger drawings with
read_drawing, which takes up to 10 MiB
Repeated 5xx
- Check System Status
- Contact support with the
request_idif it continues