API Reference

Error Handling

How errors are returned in the flex.plane GraphQL API and how to handle them in your client.

GraphQL does not use HTTP status codes for application-level errors. The API always returns HTTP 200 for valid GraphQL requests, even when the operation fails. Errors are communicated through the errors array in the response body.

Understand GraphQL errors

A successful response with no errors looks like this:

{
  "data": {
    "vm": {
      "id": "abc123",
      "name": "web-01",
      "status": "running"
    }
  }
}

When something goes wrong, the response includes an errors array alongside (potentially partial) data:

{
  "data": {
    "vm": null
  },
  "errors": [
    {
      "message": "vm not found",
      "path": ["vm"],
      "extensions": {
        "code": "NOT_FOUND"
      }
    }
  ]
}

Key fields in each error object:

FieldDescription
messageHuman-readable description of what went wrong.
pathThe field path in the query where the error occurred.
extensionsAdditional metadata, often including an error code.
GraphQL supports partial responses. A query that fetches multiple fields may succeed for some and fail for others. Always check both data and errors in your client.

Handle authorization errors

When you attempt an operation without the required role, the API returns an authorization error:

{
  "data": null,
  "errors": [
    {
      "message": "access denied",
      "path": ["createVirtualDatacenter"]
    }
  ]
}

Common causes and fixes:

SymptomCauseFix
access denied on any queryToken expired or missingRefresh your OIDC token
access denied on VDC-scoped queriesMissing or wrong FlexPlane-VDC-ID headerSet the header to a VDC you have access to
access denied on admin operationsUser lacks ADMIN roleRequest admin access from your tenant administrator
access denied on VDC managementUser lacks VDC_ADMIN role for target VDCRequest VDC admin access

If you are unsure which role a field requires, check the schema. Every protected field has a @hasRole(role: [...]) directive listing the minimum required roles:

# Requires VDC_USER or higher
vms: [VM!] @hasRole(role: [VDC_USER])

# Requires ADMIN
createVirtualDatacenter(...): VirtualDatacenter! @hasRole(role: [ADMIN])

Handle validation errors

Input validation is enforced by the @constraint directive. When you send invalid input, the error message describes which constraint was violated:

{
  "data": null,
  "errors": [
    {
      "message": "validation failed: cpus must be min=1,max=64",
      "path": ["addComputeProfile"]
    }
  ]
}

Common validation constraints in the schema:

ConstraintMeaningExample
requiredField must not be emptyname: String! @constraint(constraint: "required")
min=N,max=NNumeric rangecpus: Int! @constraint(constraint: "min=1,max=64")
ipv4Must be a valid IPv4 addressipv4: String @constraint(constraint: "ipv4")
http_urlMust be a valid HTTP/HTTPS URLchecksumFile: String! @constraint(constraint: "http_url")
hostname,max=NMust be a valid hostname with max lengthid: String! @constraint(constraint: "hostname,max=8")
Validate input on the client side before sending mutations. The constraint rules are documented in the schema and are deterministic, so you can replicate them in your frontend to give users immediate feedback.

A well-structured client should:

  1. Check for the presence of the errors array in every response.
  2. If errors is present but data is also non-null, handle the partial success case.
  3. Display meaningful error messages to users based on the message field.
  4. For authorization errors, trigger a token refresh or redirect to login.
  5. For validation errors, highlight the relevant input field in your UI.