Error Handling
How the Apso platform API reports errors, the errors you are most likely to hit, and how to resolve them. Error shapes here are the ones the platform server actually returns.
Standard error response
The platform API is NestJS-based, so errors follow the standard envelope:
{
"statusCode": 400,
"message": "…", // string, or an array of strings for validation errors
"error": "Bad Request"
}Some guarded endpoints return a richer payload with a machine-readable code and, where relevant, an upgradeUrl — see the entitlement and limit errors below.
HTTP status codes
| Status | Meaning on this API |
|---|---|
400 | Malformed request — validation failure, non-integer id on an integer route, or an unknown sort/filter field |
401 | Missing or invalid authentication |
403 | Not permitted — tenant scoping, or an entitlement/limit block |
404 | Resource not found |
429 | Rate/quota exceeded — e.g. the AI token budget |
500 | Unexpected server error |
Malformed requests → 400
A central filter maps common Postgres request errors to 400 (instead of leaking a 500):
- Non-integer id on an integer route — e.g.
GET /WorkspaceServices/5f097102. - Unknown sort/filter field — e.g.
GET /ServiceDeployments?sort=status,DESCwherestatusisn’t a column.
Only these narrow, clearly-malformed cases become 400. Genuine server faults still surface as 500, so a sustained 500 is a real bug, not a bad request.
Authentication → 401
Requests without a valid session/bearer are rejected with 401. Authentication uses BetterAuth; ensure the Authorization bearer (or session cookie) is present and current. Service API keys (apso_…) authenticate against the deployed service API, not the platform API — see API Key Management.
Entitlement & limit errors → 403
Plan limits return 403 with a code and an upgradeUrl:
code | When | Extra fields |
|---|---|---|
SERVICE_LIMIT_REACHED | Creating a service past your plan’s maxServices (e.g. a 2nd service on Free) | tier, limit, current |
TEAM_MEMBER_LIMIT_REACHED | Inviting past your plan’s maxTeamMembers (seats = members + pending invites) | tier, limit, current |
ENTITLEMENT_REQUIRED | Using a feature your tier lacks (e.g. external AWS, audit logs) | entitlement, currentTier |
WORKSPACE_NOT_FOUND | The workspace context couldn’t be resolved | — |
{
"statusCode": 403,
"error": "Forbidden",
"code": "SERVICE_LIMIT_REACHED",
"message": "Your free plan allows 1 service. Upgrade to create more.",
"tier": "free",
"limit": 1,
"current": 1,
"upgradeUrl": "/billing/upgrade"
}Resolution: upgrade the plan (the upgradeUrl), or free up capacity (delete a service, remove a member). See Service Settings.
Quota errors → 429
AI features enforce a per-workspace token budget. Exhausting it returns 429:
{
"error": "Token limit exceeded",
"message": "You have exceeded your monthly token limit. Please upgrade your plan.",
"usage": { "tokensUsed": 25000, "tokenLimit": 25000, "percentage": 100 }
}The budget resets on a rolling monthly window; it also applies before an AI plan or phase runs, so a blocked request never partially executes.
Service creation errors
The create flow surfaces the API’s error message directly. Common causes:
- An entitlement/limit block (e.g.
SERVICE_LIMIT_REACHED) — see above. - A malformed or empty prompt/name.
Read the message shown in the create dialog; it is the server’s message.
Deployment & build failures
Deployment and provisioning are asynchronous. Failure surfaces as the service’s build status = Error (red badge) or a deployment health of Failed. See Service List for how those indicators differ.
Diagnose: open the service’s Logs and Deployments sections, check the build/deploy status, and retry the deploy after fixing the cause (often a schema/scaffold error or a missing GitHub connection for code-scaffolded deploys).
Troubleshooting checklist
- Read the
codeandmessage— most platform errors are self-describing (SERVICE_LIMIT_REACHED,ENTITLEMENT_REQUIRED,Token limit exceeded). 400? Check the id format and anysort/filterfield names against the entity’s columns.401? Re-authenticate; confirm the bearer/session is attached.403with acode? It’s a plan limit or entitlement — follow theupgradeUrl.429? You’ve hit the token budget; wait for the reset or upgrade.- Deploy failed? Check Logs + Deployments; confirm the GitHub connection for code-scaffolded services.
This documents the platform API’s error behavior as implemented. Application-specific error catalogs (per generated service) follow the same NestJS envelope but define their own validation messages.