Errors
Every status code Repackage returns and what to do about it.
All errors share a single envelope:
{
"error": {
"code": "snake_case_code",
"message": "Human-readable explanation.",
"retryable": true
}
}retryable is your single signal: if true, the same request might succeed later (transient upstream issue, rate limit). If false, change the request.
Auth and plan errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | No credentials, or the session expired. |
| 401 | invalid_api_key | Key is malformed, revoked, or expired. |
| 402 | plan_limit_exceeded | Monthly quota hit. Includes limit, used, resetAt, scope. |
| 403 | feature_not_in_plan | Endpoint requires Pro and the caller is on Free. Includes feature, tier. |
| 409 | no_active_organization | Session has no org. Sign out and back in. |
Request errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Body or query parameters failed validation. |
| 400 | invalid_video_id | Couldn't resolve an 11-character video ID from the input. |
| 404 | not_found | Resource doesn't exist or isn't visible to your org. |
| 422 | unprocessable | Request shape is right but values aren't usable (e.g. private video). |
Transcript-specific errors
| Status | Code | Meaning |
|---|---|---|
| 404 | video_not_found | Video ID doesn't resolve on YouTube. |
| 422 | transcript_unavailable | Video exists but has no transcript and we couldn't generate one. |
| 422 | video_age_restricted | Video is age-gated; we can't fetch without an auth cookie. |
| 422 | video_private | Private or unlisted with restricted access. |
Server / upstream errors
| Status | Code | Retryable | Meaning |
|---|---|---|---|
| 429 | rate_limited | yes | Too many requests in the current IP / org window. |
| 500 | internal_error | yes | Something in our pipeline failed. |
| 502 | upstream_failure | yes | YouTube or a downstream service is unhappy. |
For retryable errors, exponential backoff (start at 1s, max 30s) is enough. For 429, look for Retry-After.
On the MCP side
MCP errors come back as a regular tool result with isError: true:
{
"isError": true,
"content": [
{ "type": "text", "text": "transcript_unavailable: Video exists but has no transcript." }
]
}Codes match the table above.