Error Codes & Response Shapes
Standard error codes returned by the Scrubby REST API and MCP tools, with what they mean and how to recover.
Scrubby’s REST API and MCP tools return structured errors. This page lists the codes you’ll encounter, what they mean, and what to do about them.
Response shape
REST endpoints return JSON. Successful responses have a 2xx status; errors carry a 4xx or 5xx status with a body of the form:
{
"error": "human-readable message",
"code": "machine_friendly_code",
"details": { /* optional, error-specific */ }
}
MCP tools return errors as MCP tool errors. Your editor renders the message; the same code field appears in the structured payload.
HTTP status codes
| Status | Meaning |
|---|
200 OK | Success. |
400 Bad Request | Malformed request body, missing required parameter, or invalid input. |
401 Unauthorized | Missing or invalid auth token. Re-authenticate. |
403 Forbidden | Authenticated but not authorized for this resource (wrong org, wrong role). |
404 Not Found | Resource doesn’t exist or you don’t have access. |
409 Conflict | State conflict, e.g. trying to start an index when one is already running. |
422 Unprocessable Entity | Validation failed; details in details. |
429 Too Many Requests | Rate-limited. See Rate Limits & Quotas. |
500 Internal Server Error | Server-side bug. Retry once; if it persists, file an issue. |
Common error codes
Auth
| Code | When it happens | What to do |
|---|
not_authenticated | No token, or token expired. | Reconnect from your editor or re-login on the dashboard. |
invalid_token | Token is malformed or revoked. | Generate a fresh token from your Account page. |
oauth_failed | OAuth callback failed (state mismatch, missing scope). | Retry; clear any browser-side OAuth state. See Auth & OAuth Issues. |
Repositories
| Code | When it happens | What to do |
|---|
repo_not_found | The named repo doesn’t exist or you don’t have access. | Check the owner/repo path; check the GitHub App is installed. |
repo_not_indexed | The repo isn’t indexed yet. | Run scrubby_index first. |
index_in_progress | A previous index is still running. | Wait a minute and retry, or check GET /v1/repositories/:id/index/status. |
index_failed | The last index attempt errored out. | See Indexing Stuck or Failing. |
Analysis
| Code | When it happens | What to do |
|---|
file_not_found | The path isn’t in the indexed snapshot. | Run an incremental index; the file may have been added recently. |
no_files | Changeset analysis was called with no file paths and no staged changes. | Stage some changes or pass file_paths explicitly. |
unsupported_file_type | File type isn’t supported (binary, oversized, etc.). | Skip the file; not all formats are analyzable. |
Billing
| Code | When it happens | What to do |
|---|
plan_required | An action requires a plan you don’t have. | Upgrade via Plans & Pricing. |
seat_limit_reached | Trying to invite more members than your seat count allows. | Add seats from the Team page. |
payment_failed | Stripe rejected the payment method. | Update billing in the Stripe portal. |
trial_already_used | Trying to start a second trial. | Each user gets exactly one trial. |
Webhooks
| Code | When it happens | What to do |
|---|
invalid_signature | Webhook signature failed verification. | Check secrets; signature algorithm is HMAC SHA-256 for GitHub, Stripe SDK for Stripe. |
unknown_event | Webhook event type isn’t one Scrubby handles. | Silent ignore; no action needed. |
Generic
| Code | When it happens | What to do |
|---|
validation_failed | Input failed schema validation. | Check details for the specific field. |
rate_limited | Too many requests in a short window. | Back off; retry with exponential backoff. |
internal_error | Unexpected server error. | Retry once; if it persists, contact support. |
Retry guidance
- 5xx errors: retry with exponential backoff up to 3 attempts.
429: back off based on the Retry-After header if present, otherwise wait 30 seconds.
- 4xx errors except
429: don’t retry. Fix the request and try again.
index_in_progress / index_failed: poll GET /v1/repositories/:id/index/status rather than retrying the index trigger.