# HyperOne Error messages ## Introduction [toc] HyperOne APIs are RFC7807 compliant. RFC7807 defines the basic response structure consisting of a JSON document with a mime-type `application/problem+json` containing at least fields: `type`, `title`, `detail` and `instance`. Following definition of attribute is provided: - `type` (string) - A URI reference [RFC3986] that identifies the problem type. - `title` (string) - A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4). - `status` (number) - The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem. - `detail` (string) - A human-readable explanation specific to this occurrence of the problem. - `instance` (string) - A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced. In addition, it provides extensions that allows to enter additional fields specific to the type of error. They are presented in the relevant sections below. Example error response: ```json HTTP/1.1 400 Bad Request Content-Type: application/problem+json Content-Language: en { "type": "/error/503/unavailable/", "title": "Service Unavailable", "status": 503, "detail" : "API is temporary not available. Please try again later.", "detail" : { // for localized message "$ref": "accent.com/error-messages/XXX#/xxxx" } } ``` ## Error identifier To identify the error code, the following error code are used: ```text /{namespace}/error/{http_status_code}/{code}/{subcode} ``` Field `{subcode}` is optional. Errors at the primary level are reported without "subcode". It might a one or more errors within extensions. In the case of extensions - errors using ```{subcode}`` are used. For example: ```text /core/error/resource/400/INVALID_ARGUMENT ``` ## Quota vs. Capacity In order to properly use the error type ```/core/error/503/unavailable/qos``` and ```/core/error/409/failed_precondition/quota```, the following comments must be made. - Quota – Organisations planned usage limits of capacity allocated. The platform suggests default limits and MAY accept changes to some of the limits. (409) - level: organisation / project / resource - soft limit - request required to change; can be changed upon request; platform apply default; maximum limit eg. website count, disk size, network size (/28) - Capacity – Validated on request to change soft limit - level: organisation / project / resource - hard limit - minimum and maximum limit (ranges) - QoS - Restrictions on the operation and indirect limits necessary to keep SLA (reliability) and the user within the limits of the planned usage. (503 Unavailable) eg. platform error / no_host ## Localisation Text visible in `detail` and `title` SHOULD be localized to suit client preferences, expressed with the `Accept-Language` request header. In the absence of client preferences information, message in English SHOULD be provided. ## Guidelines When writing an error message, the following rules should be taken into account: - Consider each message considering different consumers, in particular CLI, SDK, Panel. - Avoid abstract error messages - message MUST help users understand the root cause of the problem - Get rid of technical terms - message SHOULD be written in an accessible way and do not abuse abbreviations - Write concisely, but precisely - Don’t over-communicate the problem – Error messages should enable users to easily resolve a problem, not provide all information what happened - Don’t blame users – Focus on the problem, not the user action that led to the problem. - Give users a solution - If possible, consider suggesting a solution to the problem. For title of error, the following rules apply: - provide a short, human-readable summary of the problem type. - MUST NOT change from occurrence to occurrence of the problem, except for purposes of localization - MUST NOT use variables - is a title, not a full sentence - it MUST does not end with a punctuation mark - SHOULD have length of 2-3 words - it MUST start with capital letter For detail of error, the following rules apply: - provide a human-readable explanation specific to this occurrence of the problem. - MAY change from occurrence to occurrence of the problem, not only for purposes of localization - MAY use variables - SHOULD have length of 7-10 words - SHOULD not repeat raw user input - MAY contain resource data eg. state, name - SHOULD use {kind} (namespace, name) for reference resource type - is a full sentence - it MUST end with a punctuation mark - it might be more than one sentence - it MUST start with capital letter - if it is necessary to indicate a resource - indicate its name in the response, if authorization has been carried out. - in the case of a number or enumeration, consider the singular and plural form Recommended documents: - [Nick Babich, How to Write and Design User-Friendly Error Messages, Medium.com, 5 February 2020](https://medium.com/thinking-design/how-to-write-design-user-friendly-error-messages-87d0207bb902) ## Async operation error Some API operations can be time consuming. In this case, the platform MAY execute the request asynchronously by responding with the status 202 and with the header `Location` containing URL to event. If the asynchronous operation is completed, the agent should respond using the JSON Reference pointing to the appropriate language message. Then the scheduler (region) should resolve reference to provide a translated response. ## Error codes Error codes have been identified. Error codes have a hierarchy consisting of: - namespace - HTTP status code, - code - subcode (optional) Specific errors have been discussed in detail for individual codes. ### 400/INVALID_ARGUMENT The client specified an invalid argument. `INVALID_ARGUMENT` indicates arguments that are problematic regardless of the state of the platform, including existing resources, resource variant and configuration (e.g. missing argument, a malformed file name). The request will never be correct, even in the future state of the platform will change. Note that this differs from `FAILED_PRECONDITION`, which takes into account the current state of the platform. ### 409/FAILED_PRECONDITION The operation was rejected because the resource **is not in a state required** for the operation's execution. For example, the directory to be deleted is non-empty, an ```rmdir``` operation is applied to a non-directory. The request MIGHT be correct when the future state of the platform will change. For inbound requests, the following algorithm takes place to distinguish between relevant errors: - if path NOT in OpenAPI - 404 (Not Found) it still replies with a standard format error (offline check) - if path in OpenAPI and: - invalid format of parameter eg. "xyz" as ObjectId – `/error/400/INVALID_ARGUMENT` (offline check) - not available resource - `/error/403/PERMISSION_DENIED` (online check) ### 429/REQUESTS_EXHAUSTED > The HTTP **429 Too Many Requests** response status code indicates the user has sent too many requests in a given amount of time ("rate limiting"). > Note that this specification does not define how the origin server identifies the user, nor how it counts requests. For example, an origin server that is limiting request rates can do so based upon counts of requests on a per-resource basis, across the entire server, or even among a set of servers. Likewise, it might identify the user by its authentication credentials, or a stateful cookie. Reserved for gauge like limits/metrics (time-related). Errors which are relatdd just to a value (like counter) without time taken into account should be reported using ```/error/409/FAILED_PRECONDITION/QUOTA_EXHAUSTED``` Reserved mainly for platform request api throttling and QoS. ### 401/UNAUTHORIZED Error status response code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource. ### 403/PERMISSION_DENIED > The caller does not have permission to execute the specified operation. `PERMISSION_DENIED` must not be used for rejections caused by exhausting some resource (use `RESOURCE_EXHAUSTED` instead for those errors). `PERMISSION_DENIED` must not be used if the caller can not be identified (use `UNAUTHENTICATED` instead for those errors). This error code does not imply the request is valid or the requested entity exists or satisfies other pre-conditions. ### 503/UNAVAILABLE > The service is currently unavailable. This is most likely a transient condition, which can be corrected by retrying with a backoff. Note that it is not always safe to retry non-idempotent operations. Header should include header `Retry-After` for indication for client to know if and after what delay (when) to retry the request. ## Extensions ### Metadata of error regarding permission Permission problems can have various causes: - roles which actor have does not have required permissions - actor don't have any roles - policy condition is not met Permission error message MUST specify: - `who` - actor (to reduce error mistake in case of impersonate) - `where` (to make obvious if it's related to main resource or attribute/param value) - `what` (to specify missing permission) Permission problem MAY be related to user input eg. missing permission for ```*.*.use``` - in `field` or in path. ```json { "type": "/core/error/403/forbidden", "title": "Forbidden", "detail" : "Operation not authorized.", "status": 403, "permission": [{ "parameter": { // _optional_, apply if permission is parameter-required "in": "body", // "query", "header", "path", "cookie" or "body", // follow OpenAPI fixed fields syntax: // http://spec.openapis.org/oas/v3.0.3#fixed-fields-9 "field": "service", // for "query", "header", "path", "cookie" - match to "name" in parameter // for "body" – follow RFC6901 - JSON Pointer }, // A short, human-readable summary of the problem type; follow RFC7807 "title": "Permission required", // A human-readable explanation specific to this occurrence of the problem; follow RFC7807 "detail" : "Required permission 'website/instance/create' on '{resource.id}' to '{actor.name}'" , // who (user who perform operation or external provider) "actor": "/iam/user/name@domain", // where "resource": "{resource.uri}/subresource/{subresourceId}", //what "value": "website/instance/create" }] } ``` ### Metadata of error regarding pre-required operation Pre-required operation problems can have various causes: - quota increase missing Problem MAY be related to user input eg. missing permission for ```*.*.use``` - in `field` or in path. ```json { "type": "/core/error/409/failed_precondition", "title": "Failed precondition", "status": 409, "detail" : "Operation can not be executed in the current system state.", "operation": [{ "parameter": { // optional "parameter", depends on limit type, eg: // resize of disk size - user param // project limit numbers of resource - not user param ) "in": "xx", // "query", "header", "path", "cookie" or "body", // follow OpenAPI fixed fields syntax: // http://spec.openapis.org/oas/v3.0.3#fixed-fields-9 "field": "", // for "query", "header", "path", "cookie" - match to "name" in parameter // for "body" – follow RFC6901 - JSON Pointer "schema": "", // for "query", "header", "path", "cookie" - OpenAPI Parameter Object // for "body", "limit" - follow JSONSchema }, // A short, human-readable summary of the problem type; follow RFC7807 "title": "Quota exceeded", // A human-readable explanation specific to this occurrence of the problem; follow RFC7807 "detail" : "Operation results in exceeding quota limit '{quota.name}' allowed maximum of 5 by an additional 3.", "resource": "/iam/project/xxxxx/quota/xx" }] } ``` ### Metadata of error regarding argument ```json { // A URI reference [RFC3986] that identifies the problem type; follow RFC7807 "type": "/core/error/400/invalid_argument" , // A short, human-readable summary of the problem type. ;follow RFC7807 "title": "Invalid argument", "status": 400, // A human-readable explanation specific to this occurrence of the problem; follow RFC7807 "detail" : "Operation was rejected due invalid argument.", "argument": [ { "parameter": { "in": "body", // "query", "header", "path", "cookie" or "body"; // follow OpenAPI fixed fields syntax: // http://spec.openapis.org/oas/v3.0.3#fixed-fields-9 "field": "", // for "query", "header", "path", "cookie" - match to "name" in parameter // for "body" – follow RFC6901 - JSON Pointer "schema": "", // for "query", "header", "path", "cookie" - OpenAPI Parameter Object // for "body" - follow JSON Schema }, "type": "/core/error/400/invalid_argument/minimum", // A URI reference [RFC3986] that identifies the problem type. // follow RFC7807 "title": "Out of range", // A short, human-readable summary of the problem type; no argument for translation // follow RFC7807 "detail" : "Value is less than minimum allowed value (${min}).", // A human-readable explanation specific to this occurrence of the problem, // might have argument for translation; follow RFC7807 } ] } ``` ## Appendix - [List of Error Messages (including type, extensions, detail and localization)](https://docs.google.com/spreadsheets/d/1wovYZ95KjTQKvAM403Yy26rStCRT_GvwIAKktZg6yy8/edit#gid=1821541720) ## Further reading keywords - micro copy - ux writting - kinet reftra (?), micro copy the complete guide