Minds Team

Errors & Limits

Understanding API errors, status codes, and plan-based resource limits, including the error response format, rate limits, and common 4xx causes.

Understanding API errors, rate limits, and plan restrictions.

Error Response Format

All errors follow a consistent format:

{
  "statusCode": 400,
  "statusMessage": "Name is required",
  "message": "Name is required",
  "url": "/api/v1/minds",
  "error": true
}
FieldDescription
statusCodeHTTP status code
statusMessageHuman-readable error description (set per-error by the handler — for validation errors this is the specific issue, e.g. "Mind not found" or "Invalid Mind ID format")
messageSame content as statusMessage for v1 errors. Reserved for stack/extra context in 5xx responses on debug builds.
urlThe request path (added by Nuxt H3)
errortrue for error responses (added by Nuxt H3)
dataOptional. Present only when an error carries machine-readable detail (see below). Absent on most errors.

Always rely on statusCode for programmatic handling and statusMessage (or message) for the human-readable reason. The url and error fields are convenience metadata from the underlying framework.

The data field

Some errors attach a data object with structured detail you can branch on instead of parsing statusMessage. Two shapes you will encounter:

  • data.code — a stable machine-readable error code. Currently "PLAN_LIMIT" on plan-limit 403s, alongside limitType, currentPlan, limit, and current. See Plan Limits below.
  • data.expectedNoise — internal telemetry metadata, set to true on routine 401s and on a few 404s that are almost always crawler probes. It tells our error monitoring to drop the event so real faults are not buried. It is not part of the public contract: ignore it, and do not branch on it.

Treat any other data key as reserved. Unknown keys may be added at any time, so read the fields you care about rather than asserting on the whole object.

HTTP Status Codes

2xx Success

CodeStatusDescription
200OKRequest succeeded
201CreatedResource created successfully (e.g. POST /minds, POST /minds/{id}/knowledge)
202AcceptedRequest accepted for asynchronous processing (e.g. POST /minds/{id}/knowledge with keywords)
204No ContentRequest succeeded, no response body (e.g. DELETE /minds/{id}/knowledge/{itemId})

4xx Client Errors

CodeStatusDescription
400Bad RequestInvalid request parameters
401UnauthorizedMissing or invalid API key
403ForbiddenAccess denied or plan limit reached
404Not FoundResource doesn't exist
415Unsupported Media TypeWrong Content-Type header
422Unprocessable EntityThe request is well formed but cannot be carried out, for example starting an Audience validation when the Audience has fewer than 10 ready Minds (AUDIENCE_TOO_SMALL)
429Too Many RequestsRate limit exceeded

5xx Server Errors

CodeStatusDescription
500Internal Server ErrorServer-side error
503Service UnavailableService temporarily unavailable

Common Errors

400 Bad Request

Missing Required Field:

{
  "statusCode": 400,
  "statusMessage": "Name is required"
}

Invalid Input:

{
  "statusCode": 400,
  "statusMessage": "File too large: document.pdf (55.2MB). Maximum size is 50MB."
}

401 Unauthorized

Missing API Key:

{
  "statusCode": 401,
  "statusMessage": "Unauthorized",
  "message": "Unauthorized",
  "url": "/api/v1/minds",
  "error": true,
  "data": {
    "expectedNoise": true
  }
}

The data.expectedNoise flag is internal telemetry metadata, not part of the contract — see The data field above.

Solution: Include the Authorization header:

-H "Authorization: Bearer minds_your_api_key"

403 Forbidden

Plan Limit Reached:

{
  "statusCode": 403,
  "statusMessage": "Starter plan limit reached",
  "message": "Starter plan limit reached",
  "url": "/api/v1/minds",
  "error": true,
  "data": {
    "code": "PLAN_LIMIT",
    "limitType": "sparks",
    "currentPlan": "premium",
    "limit": 100,
    "current": 100
  }
}

Branch on data.code === "PLAN_LIMIT" and data.limitType rather than on the message text — see Plan Limits below.

Access Denied:

{
  "statusCode": 403,
  "statusMessage": "Access denied"
}

404 Not Found

Resource Doesn't Exist:

{
  "statusCode": 404,
  "statusMessage": "Mind not found"
}

415 Unsupported Media Type

Wrong Content-Type:

{
  "statusCode": 415,
  "statusMessage": "Unsupported Content-Type. Use application/json for links or multipart/form-data for files"
}

Solution: Use the correct Content-Type header:

  • application/json for JSON requests
  • multipart/form-data for file uploads

429 Too Many Requests

Rate Limit Exceeded:

{
  "statusCode": 429,
  "statusMessage": "Too many requests. Please try again later."
}

Rate Limits

The v1 API enforces a per-account fixed-window limit. The default deployment limit is 300 requests per minute, but operators can tune it, so integrations must use response headers rather than hard-code that number:

  • RateLimit-Limit — current per-minute ceiling
  • RateLimit-Remaining — requests remaining in the active window
  • Retry-After — seconds to wait after a 429

The limiter is applied per application instance and may fail open during limiter infrastructure errors. Keep concurrency bounded even when no 429 is observed.

Plan Limits

See the generated plan-limit table for the current public defaults. Account-specific contract overrides may differ, so data.limit and data.current in an authenticated error response are authoritative for that request. The Starter plan is represented as "premium" in API payloads.

Mind-limit example

Error when limit reached:

{
  "statusCode": 403,
  "statusMessage": "Starter plan limit reached",
  "message": "Starter plan limit reached",
  "url": "/api/v1/minds",
  "error": true,
  "data": {
    "code": "PLAN_LIMIT",
    "limitType": "sparks",
    "currentPlan": "premium",
    "limit": 100,
    "current": 100
  }
}

Reading a plan-limit error

Every plan-limit 403 carries the same data shape, so one handler covers all of them:

  • code — always "PLAN_LIMIT" for this class of error.
  • limitType — which allowance was exhausted. Values reachable from the v1 API are "sparks" (minds owned), "flows" (chats created, including panel sessions), "messages" (messages within one chat or panel), and "groupMembers" (minds in a single group).
  • currentPlan — the caller's plan tier: "free", "premium", or "team".
  • limit — the allowance for that plan and limit type.
  • current — the caller's usage at the time of the request.

statusMessage is human-readable and its wording may change; code and limitType are the stable contract.

Knowledge Upload Limits

  • File Size: Maximum 50MB per file (all plans)
  • Storage: No explicit storage limits currently enforced

API Key Limits

  • Maximum Keys: No cap is currently enforced. Delete keys you no longer use rather than letting them accumulate.

Audience validation failures

Starting an Audience validation on an Audience with fewer than 10 ready Minds returns 422 with the code AUDIENCE_TOO_SMALL. An Audience larger than your plan allows in a Study is refused with the standard plan-limit error described above.

After a successful start, the validation runs in the background, so most failures are not HTTP errors. Read them from the failure field of the validation batch instead. A batch can end with one of these codes:

CodeMeaning
AUDIENCE_TOO_SMALLThe Audience has fewer than 10 ready Minds. Also returned as 422 when you start a validation
MINDS_NEED_RETRAININGMinds in the Audience need retraining before they can answer
NOT_ENOUGH_QUESTIONSFewer than 8 questions fit the Audience, so nothing was asked
NOT_ENOUGH_RESPONSESThe run needs more synthetic responses than you have left
NO_FITTING_SURVEYNo published survey fits the Audience
NO_USABLE_SURVEYNone of the surveys can validate this Audience
NO_SCORENone of the surveys could be scored for this Audience
RUNS_REFUSEDThe validation run could not be started
SURVEY_NOT_FOUNDA named survey could not be found
SURVEY_FILES_UNREADABLEThe uploaded survey files could not be read
SURVEY_RESULTS_NOT_FOUNDThe uploaded files contain no published results to compare against
VALIDATION_TOO_LARGEThe validation would ask for more than 30,000 answers

Best Practices

Error Handling

Always handle errors:

async function requestJson(url, apiKey, data) {
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
  });

  const text = await response.text();
  let result = null;
  if (text) {
    try {
      result = JSON.parse(text);
    } catch {
      if (response.ok) throw new Error('Expected a JSON response');
    }
  }
  if (!response.ok) {
    throw Object.assign(new Error(result?.statusMessage || result?.message || `HTTP ${response.status}`), {
      status: response.status,
      data: result?.data,
      retryAfter: response.headers.get('Retry-After')
    });
  }
  return result;
}

Retry Logic

Implement smart retries:

  • Retry reads on transient 429 or 5xx responses with bounded exponential backoff; honor Retry-After. Retry writes only where the endpoint documents idempotency, preserving the same key and request body. After an ambiguous timeout, check the existing resource or job before submitting again.
  • Use exponential backoff
  • Set maximum retry attempts
  • Don't retry on 4xx errors (except 429)

Monitoring

Track your usage:

  • Log rate limit headers
  • Monitor error rates
  • Set up alerts for recurring errors
  • Track response times

Upgrade When Needed

Upgrade your plan if you:

  • Hit rate limits frequently
  • Need more minds
  • Require larger file uploads
  • Want priority support

View Plans

Getting Help

Check Status

Monitor our service status:

Contact Support

If you experience:

  • Persistent 500 errors
  • Incorrect rate limiting
  • Unexpected behavior

Contact us:

Review Documentation

Status Codes Reference

Quick reference for all HTTP status codes:

2xx Success
├─ 200 OK
└─ 201 Created

4xx Client Error
├─ 400 Bad Request
├─ 401 Unauthorized
├─ 403 Forbidden
├─ 404 Not Found
├─ 415 Unsupported Media Type
└─ 429 Too Many Requests

5xx Server Error
├─ 500 Internal Server Error
└─ 503 Service Unavailable