API error handling

The 10Duke Scale API uses conventional HTTP response codes to indicate the success or failure of an API request.

  • Codes in the 2xx range indicate success.

  • Codes in the 4xx range indicate a failure related to the information provided in or in context of the request (for example, a required parameter was omitted, an entity didn’t exist, or a heartbeat was sent too early).

  • Codes in the 5xx range indicate an error with 10Duke Scale servers (these are rare).

Codes in the 3xx range are currently not used. However, we recommend that API clients implement best practice security for HTTP redirects. The 10Duke Scale API may use redirects in the future, and the 304 Not Modified code may also be used in the future.

In addition to the HTTP status code, the API provides descriptive information when possible.

Note: In the case of an API error response, the API client must take action other than immediately retrying the same request. Notes about recommended actions or corrective measures are included with the HTTP response codes in this article.

General error responses

In most cases, the error body (payload) response from the 10Duke Scale API has the same shape.

The exceptions are:

  • Responses from earlier tiers in the network, such as firewalls, load balancing, and REST routing errors

  • License consumption denial responses from the 10Duke Scale License Checkout API

General HTTP error response format

The response header:

HTTP/1.1 {STATUS CODE} {STATUS NAME}
Date: 
Content-Type: application/json; charset=UTF-8
Content-Length: 104
Connection: keep-alive

The response body (payload):

{
  "error":"{STATUS NAME}",
  "code":{STATUS CODE},
  "description":"An error description"
}
Attribute Description
code The HTTP status code of the response (for example, 400).
error The error name or reason for the status code (for example, Bad Request).
description An error description providing more detail about why the request failed.

General HTTP response status codes

The following are the HTTP response status codes used by the 10Duke Scale API.

Status code Description
200 OK Everything worked as expected.
201 Created The request was successful, and a new entity was created as a result.
204 No Content There is no content to send for this request, but the headers may be useful. This status indicates success and is commonly used with API operations that delete entities (but not all delete operations).
400 Bad Request The request cannot be processed, typically due to a missing required parameter or a parameter that is not of the correct type. The API client must change the parameters/payload.
401 Unauthorized Authentication information is invalid or missing. Create or renew the API authentication token in the API client.
403 Forbidden The API token doesn’t have permissions to perform the request.
404 Not Found A provided entity identifier or natural key cannot be found. For more information, see the description field in the error response body, when available.
409 Conflict This can be caused by concurrent attempts to modify the same resource in separate API requests. The API client must refresh its data and start the modifying action again.
429 Too Many Requests This can be caused by too many requests to the API too quickly or by sending a license heartbeat too early. Follow the instructions of the specific API endpoint that returned the response. If no specific instructions are available, the recommended approach is an exponential backoff.
5xx Server Error The cause is internal to the 10Duke Scale API (these are rare).

License consumption error responses

License consumption error responses refer to error responses from the License Checkout API when the API client attempted to check out or release a license in enforced consumption, to start or end metered consumption for a license, or to send a heartbeat for a license lease.

In most cases where a license consumption error occurred, the License Checkout API still returns HTTP 200 OK. This is due to a multi-entity response format where some parts may have been successful while some parts failed with an error.

When checking out a license, starting metered consumption, or sending a heartbeat, the response contains a JSON array of JSON Web Tokens (JWT), a JWT for each requested license. When releasing a checkout or ending metered use, the response contains an array of JSON objects, each representing the outcome for a specific license.

This means that to catch an error, for example, with a particular license checkout, the API client must parse the multi-entity response and handle it part by part. Each part holds the information on whether the request for the corresponding license was successful or failed.

In cases when there’s a fundamental error in the API request (for example, the license consumer cannot be found), the License Checkout API returns a general HTTP error.

License consumption error response format

The license checkout error uses the general HTTP response header.

The response format for each token in the JWT body:

[
  {
    "iat" : {ISSUED AT},
    "jti" : "{JWT ID}",
    "status" : "{ERROR STATUS}",
    "errorCode" : "{ERROR CODE}",
    "errorDescription": "An error description"
  }
]

The following are the claims relevant to error cases. See more details on the license checkout response and JWT claims if needed.

Claim Description
status If this claim has the value error, the client application must analyze the errorCode value to determine if it needs to communicate error details to the user.
errorCode The error code. Even if the client application doesn’t understand or know the given error code, it must treat the outcome as an error.
errorDescription An error description providing more detail about why the request failed. Note that this value is not localized, and we recommend that you don’t show it in your application UI. For UI messages, we recommend that you use the errorCode value to look up a message from your application’s language resources.

License consumption error codes

Error code Description
clientHwIdMismatch The request failed because the license model binds the checkout to the hardware ID, and the hardware ID in the request doesn’t match the one provided at checkout. This error applies to heartbeat and release/end metered use requests.
clientVersionNotAllowed The request failed because the license doesn’t allow the client application version. This error only applies to heartbeat requests and can occur, for example, if the client application has been upgraded after the checkout. (Releasing/ending metered use is allowed even if the client application version is not allowed, and a checkout/start metered use request returns noLicenseFound instead.)
insufficientQuantity The checkout for a seat, use count, or use time from a license failed because the requested quantity exceeded the remaining quantity in the license. This error applies to checkout/start metered use and heartbeat requests.
leaseIdNotFound The request failed because the license has been deleted. This error applies to heartbeat and release/end metered use requests.
licenseCheckoutExpired The request failed because the checkout has expired or the license has been revoked. This error applies to heartbeat requests.
licenseConsumerNotFound The request failed because no license consumer was associated with the call. This error is given, for example, if the license consumer associated with a license key has been deleted but the license key has been left intact. The error applies to checkout/start metered use requests that use a license key.
licenseConsumerVsConsumptionMismatch The request failed because the checkout was made for a different license consumer than the one given in the request. This error applies to heartbeat and release/end metered use requests.
licenseConsumptionClaimFieldsMissing The request failed because it doesn’t specify all the client application claims required by the license checkout binding type, such as the client’s hardware ID claim. This error applies to heartbeat and release/end metered use requests.
licenseInvalid The request failed because the license is currently not valid (for example, the license may have expired or may not be valid yet). This error applies to checkout/start metered use requests that specified a value in the licenseId parameter.
licenseKeyVsLeaseIdMismatch The request failed because the license key given in the request is for a different license than the checkout is for. This error applies to heartbeat and release/end metered use requests.
noLicenseFound The request failed because no license qualified for use based on the license consumption claims provided by the client application. This error is given, for example, if the licenses accessible to the license consumer require a different client application version than the version given in the checkout request. This error applies to checkout/start metered use requests.

Best practices for handling license consumption errors

  • When handling errors in a license consumption response, it’s essential to identify which parts failed and why. This includes inspecting each token’s errorCode and errorDescription.

  • We recommend that in error cases, the client application confirms further actions with the user of the application.

Example error responses

Here are some examples of API error responses.

Entity not found with given ID

All “read by ID” API endpoints respond with a Not Found error if the requested entity is not found with the given ID.

Example HTTP response headers in this case:

HTTP/1.1 404 Not Found
Date: Thu, 19 Jan 2023 18:25:51 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 99
Connection: keep-alive

An example HTTP response body:

{
  "error":"Not Found",
  "code":404,
  "description":"{ENTITY TYPE} [id=f83a406f-a1b2-4fc7-b687-00e3dcb3f0b3] does not exist"
}

In description, {ENTITY TYPE} is the API object type that was requested. For example, when requesting a Licensee by ID f83a406f-a1b2-4fc7-b687-00e3dcb3f0b3:

"description":"Licensee [id=f83a406f-a1b2-4fc7-b687-00e3dcb3f0b3] does not exist"

Checkout failed, license consumer not found

The license consumer that the license checkout is for is specified either in the sub claim in the OpenID Connect (OIDC) ID Token or in the licenseConsumerId header. If a license consumer by the given ID is not found, this results in an HTTP Not Found error response.

Example HTTP response headers in this case:

HTTP/1.1 404 Not Found
Date: Thu, 19 Jan 2023 18:25:51 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 99
Connection: keep-alive

An example HTTP response body:

{
  "error":"Not Found",
  "code":404,
  "description":"No such user: f83a406f-a1b2-4fc7-b687-00e3dcb3f0b3"
}

Another example HTTP response body:

{
  "error":"Not Found",
  "code":404,
  "description":"License consumer not found, make sure either licenseConsumerId is specified as a request parameter or use OIDC Id Token based API authorization"
}

Checkout failed, high concurrency/contention

Contention may happen if multiple client applications try to check out a seat from the same license at the exact same time. This happens if the concurrent checkout requests arrive within a timeframe of 100-200 milliseconds, and there are more requests than there are free seats for the license.

Example HTTP response headers in this case:

HTTP/1.1 409 Conflict
Date: Thu, 19 Jan 2023 18:25:51 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 104
Connection: keep-alive

An example HTTP response body:

{
  "error":"Conflict",
  "code":409,
  "description":"Contention to license suspected, locking checkout failed"
}

Checkout failed, no remaining quantity

A license may run out of capacity if there are more license consumers than the license has seats for, or if the use count or use time granted in the license has been consumed.

A license may also run out of capacity when the license model limits the number of concurrent devices per seat. For example, if an application can be used on two devices at the same time, and a user is already using it on a workstation and laptop, an attempt to check out the same seat on a third computer fails.

Example HTTP response headers in this case:

HTTP/1.1 200 OK
Date: Thu, 19 Jan 2023 18:25:51 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 99
Connection: keep-alive

An example HTTP response body, a JSON array of JWTs and a failed license check JWT body, looks like this:

[
  {
    "iat":1645784409,
    "jti":"d546a135-489e-4a77-accb-3798ff28fc74",
    "productName":"ThreeDee",
    "status":"error",
    "errorCode":"insufficientQuantity",
    "errorDescription":"No capacity left on license: ..."
  }
]

Heartbeat failed, lease ID not found

The License Checkout API may not find the lease ID if the checkout has been released, for example, by an administrator user through the 10Duke Scale UI console. In this case, the client application is holding a stale token and receives an error response when sending a heartbeat for the license checkout.

Example HTTP response headers in this case:

HTTP/1.1 200 OK
Date: Thu, 19 Jan 2023 18:25:51 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 104
Connection: keep-alive

An example HTTP response body, a JSON array of JWTs and a failed license check JWT body, looks like this:

[
  {
    "iat" : 1645784409,
    "jti" : "d546a135-489e-4a77-accb-3798ff28fc74",
    "status" : "error",
    "errorCode" : "leaseIdNotFound",
    "errorDescription": "The lease id: ... was not found"
  }
]