Error Handling
Every LTIAAS error has the same envelope: a status, a human-readable error name, and a details object carrying a machine-readable code.
{
"status": 403,
"error": "Forbidden",
"details": {
"message": "INACTIVE_SERVICE",
"service": "Deep Linking"
}
}
Branch on details.message, not on the prose. The extra keys in details vary by error and tell you which field, service or value caused it.
Validation Errors
Malformed requests return 400 with a list of every field that failed, rather than stopping at the first:
{
"status": 400,
"error": "Bad Request",
"details": {
"errors": [
{ "field": "clientId", "message": "Missing 'clientId' parameter." },
{ "field": "user", "message": "Parameter 'user' should be a non-empty string or positive integer." }
]
}
}
Nested objects — user, context, resource, authConfig — stop validation as soon as they fail, so a bad user object may mask problems further down the body. Fix what you are shown, then re-send.
Common Failures
INVALID_ACCOUNT_TYPE — 403
The account is a Launch account, not a Connect one. Accounts are one or the other; you cannot use Connect endpoints with a Launch key.
UNREGISTERED_TOOL — 404
No tool with that clientId on this account. Usually a typo, or a client ID copied from a different environment. List your tools to check.
INACTIVE_TOOL — 403
The tool exists but is deactivated. Activate it.
INACTIVE_SERVICE — 403
The service this endpoint needs is off for your account. details.service names it. Enable it in the portal under API Settings — and remember the tool also needs the matching permission.
INVALID_METADATA_PARAMETER — 400
The metadata value is unknown or expired. Metadata lives for ten minutes from the start of the launch. If this appears intermittently, something in your Launch URL handler is slow — most often a login or consent step that should happen before the launch begins.
INVALID_BEARER_AUTHORIZATION_HEADER — 401
Missing, malformed or wrong API key. The header must read exactly Bearer <API_KEY>.
INVALID_REDIRECT_URI_PARAMETER — 400
The tool tried to be redirected somewhere not in its redirectionUris. Ask the vendor for their full list and update the registration. This is the most common failure when onboarding a new tool.
MONTHLY_TRIAL_LAUNCH_QUOTA_REACHED — 403
A trial account has used its monthly launches. details.description explains. Upgrade to continue.
DUPLICATE_NONCE — 400
The tool replayed a nonce within the 30-second window. Almost always means the user double-clicked or the iframe loaded twice; if it happens on every launch, the tool's OIDC implementation is at fault.
Errors from Your Own Endpoints
When LTIAAS calls your Launch URL or Service URL and the call fails, the failure is reported with the upstream details attached:
{
"status": 500,
"error": "Internal Server Error",
"details": {
"message": "HTTP Request error: ...",
"externalUrl": "https://yourlms.com/lti-services",
"bodyReceived": "...",
"externalError": true
}
}
externalError: true means the problem is on your side, not LTIAAS's. externalUrl tells you which of your endpoints, and bodyReceived shows what you returned — usually enough to spot a schema mismatch immediately.
Unexpected Errors
A 500 with only an errorId means something failed inside LTIAAS:
{
"status": 500,
"error": "Internal Server Error",
"details": { "errorId": "8f3c2a1b9d7e" }
}
Send that errorId to support — it identifies the logged failure exactly.
Debugging a Launch That Shows a Blank Frame
Because launches run in an iframe, errors are easy to miss. In order:
- Open the failing URL in its own tab. Errors are JSON and readable once they are not inside a frame.
- Check the network tab for a non-2xx from
your.ltiaas.comand read itsdetails.message. - Log the decoded payload at your Launch URL. If nothing arrives, the failure is earlier — between the tool and LTIAAS — and the tool's
redirectionUrisare the first thing to check. - Check the tool's own error page. Once LTIAAS has handed off, a blank frame is often the tool rejecting the ID Token — usually a keyset it cannot reach, or a deployment ID that does not match what it was configured with.
