Error reference

invalid_request

HTTP 400 retryable: false REST and MCP

The request was authenticated and understood, but a field in it does not satisfy the schema or a hand-written check the route applies before doing any work.

Why it happens

Two different layers produce this code. The outer one is the error handler: a Zod parse failure or a JSON syntax error is caught centrally and converted, and the response carries a details.fields array naming each path that failed, so you do not have to guess which key was wrong. The inner one is a set of explicit checks that a schema cannot express, and those are the ones worth knowing about, because they are where a syntactically valid request still gets refused.

Every condition below was read in the implementation at the file and line given. They are the branches that raise this code, not a summary of what the name suggests.

How to fix it

  1. Read details.fields on the response. It is a deduplicated list of the failing paths and it is populated for every schema failure, so it names the key rather than describing it.
  2. Strip CR and LF from the subject and from every recipient address before sending. An address assembled from a display name and a user-supplied string is the usual source.
  3. Deduplicate recipients yourself before counting against the 25-unique-recipient cap, because the server counts the deduplicated union of to, cc and bcc.
  4. Do not retry unchanged. This code is not retryable, and the same body will fail the same way.

Why it works this way

The header-injection check rejects the whole request rather than stripping the offending characters. Silently rewriting a subject would mean the message that went out is not the message you asked for, and the caller would have no way to notice.

Messages you will see

The message field is written for a human reading a log and is not a contract value. Branch on code instead. These are the exact strings this code is sent with today, listed so that a search for one of them lands here.

Where it appears

These are the documented surfaces that raise it. The REST base is https://api.emailforagents.ai/v1, and the remote MCP endpoint is https://mcp.emailforagents.ai/mcp.

The response

Read request_id off the body or the x-request-id header before doing anything else. It is the only handle on one specific attempt, and for a 503 it is the only handle at all, because the underlying detail stays server-side.

HTTP/1.1 400
content-type: application/json
x-request-id: req_...

{
  "error": {
    "code": "invalid_request",
    "message": "The request does not match the required format. Check the fields and JSON syntax.",
    "request_id": "req_...",
    "retryable": false
  }
}

Verified against packages/api/src/index.ts:83. The status comes from ERROR_STATUS in packages/contracts/src/errors.ts, which is the one place a code is mapped to a status.

All error codes · Documentation · Quickstart