Skip to main content

Error Handling

GraphQL handles errors differently from REST APIs. This page explains the error response format and how to handle common scenarios.


Key Difference from REST

GraphQL always returns HTTP 200, even when there are errors. You cannot rely on HTTP status codes to detect failures. Instead, check the response body for an errors array.

Always check for errors

A successful HTTP 200 response can still contain errors. Always check both the data and errors fields in the response.


Response Structure

Every GraphQL response can contain two top-level fields:

{
"data": { },
"errors": [ ]
}
FieldWhen present
dataAlways present when the query is valid (may contain null values if some fields errored)
errorsOnly present when something went wrong

There are three possible outcomes:

Success — data only

{
"data": {
"certificate": {
"name": "web-server.example.com",
"status": "ACTIVE"
}
}
}

Total failure — errors only (or data is null)

The query itself was invalid, or authentication failed:

{
"errors": [
{
"message": "Unauthorized",
"extensions": {
"code": "UNAUTHENTICATED"
}
}
]
}

Partial success — both data and errors

Some fields resolved, others failed. GraphQL returns what it can and reports errors for the rest:

{
"data": {
"certificate": {
"name": "web-server.example.com",
"validity": null
}
},
"errors": [
{
"message": "Unable to resolve validity details",
"path": ["certificate", "validity"]
}
]
}

The path field tells you exactly which field in the response errored.


Error Object Format

Each error in the errors array has these fields:

FieldDescription
messageHuman-readable description of the error
locationsWhere in the query string the error occurred (line and column)
pathThe response field path that errored (e.g., ["certificate", "validity"])
extensionsAdditional metadata, often including an error code

Common Error Scenarios

Authentication failure

Cause: Missing or invalid tppl-api-key header.

{
"errors": [
{
"message": "Unauthorized",
"extensions": { "code": "UNAUTHENTICATED" }
}
]
}

Fix: Verify your API key is correct and included in the tppl-api-key header.

Invalid query syntax

Cause: Malformed GraphQL (missing braces, typos, etc.).

{
"errors": [
{
"message": "Syntax Error: Expected Name, found \"}\"",
"locations": [{ "line": 3, "column": 1 }]
}
]
}

Fix: Check your query syntax. Use the Interactive Playground for syntax validation as you type.

Unknown field

Cause: Requesting a field that doesn't exist on a type.

{
"errors": [
{
"message": "Cannot query field \"hostname\" on type \"Certificate\". Did you mean \"fingerprint\"?",
"locations": [{ "line": 3, "column": 5 }]
}
]
}

Fix: Check the type reference page for available fields.

Missing required argument

Cause: Omitting a required argument (marked with ! in the schema).

{
"errors": [
{
"message": "Field \"certificate\" argument \"fingerprint\" of type \"ID!\" is required but not provided.",
"locations": [{ "line": 2, "column": 3 }]
}
]
}

Resource not found

Cause: The requested resource doesn't exist.

{
"data": {
"certificate": null
}
}

This is not an error — it's a valid response indicating no certificate exists with that fingerprint. Nullable return types (without !) can return null.

Pagination limits exceeded

Cause: Requesting more items than the maximum page size.

{
"errors": [
{
"message": "Argument \"first\" must be between 1 and 100"
}
]
}

Fix: Keep first and last values at 100 or below. See Pagination.


Handling Errors in Code

Here's a robust error handling pattern:

async function graphqlRequest(query, variables = {}) {
const response = await fetch('https://api.venafi.cloud/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'tppl-api-key': process.env.CM_API_KEY,
},
body: JSON.stringify({ query, variables }),
});

const result = await response.json();

if (result.errors) {
for (const error of result.errors) {
console.error(
`GraphQL error: ${error.message}`,
error.path ? `at path: ${error.path.join('.')}` : ''
);
}
}

return result;
}

Next Steps