Skip to content

API Error: 400 {"type":"error","error":{"type":"invalid_request_error","message":"tools.48.custom.name: String should have at most 64 characters"}}

One of the tool definitions your client sends with every request has a name that is too long, and the API rejects the request at schema validation before any model runs. This one is unusual in its family because it has nothing to do with your conversation: it is a property of your configuration, so a fresh session fails on its very first message, and /clear, /compact and /rewind are all guaranteed to do nothing. It is not a context-length problem, not a quota, not a key, and not the model failing — the model was never handed the request.

The name being measured is not the name you wrote

Two numbers in that message are both pointing somewhere other than where you will instinctively look.

tools.48 is an index into the assembled tool array, not into your config file. Your client builds one flat list for every request: its own built-in tools, then every tool exposed by every connected MCP server, plus anything plugins or skills contribute. Counting to the 48th entry in your MCP configuration will land you on the wrong tool, and if you have fewer than 49 tools declared anywhere you will conclude the error is nonsense. It is not — you are being told about a list you never wrote down.

The name that got measured is namespaced. Tools coming from an MCP server are prefixed so that two servers can both expose a tool called search without colliding. The prefix contains the server name, so your real budget is the limit the message states minus the prefix your client adds. A tool whose own name is comfortably short can still be rejected.

That is the whole point of this page, so here it is as a verdict: the cheapest fix is usually to rename the server, not the tool. Shortening the server name shortens every tool it exposes at once, it is a change you own even when the server is third-party code you do not control, and it takes one line of configuration. People reliably reach for the tool name first — which is the half of the string that is usually not theirs to change.

The rest of what a 400 invalid_request_error implies — nothing ran, nothing was billed for output, the result is deterministic — applies here exactly as it does across the family, and is set out on the request-body parse failure page.

Is retrying useful?

No, and this is the most clearly futile retry of the whole set.

The other 400s at least depend on conversation state that changes as you work. This one depends on a configuration file that is identical on every request until you edit it. Every request in this session, and every request in every future session started with the same configuration, carries the same oversized name.

The official SDKs retry connection errors, rate limits and 5xx responses with backoff and exclude 400 on purpose. If you added your own retry wrapper, exclude it too — otherwise a misconfigured server turns every prompt into a burst of identical rejected requests.

There is one thing worth doing twice, and it is not a retry: after you shorten a name, the next request may name a different index. That is not the fix failing; it is a second offender that was behind the first. Which is why the next section is about measuring all of them rather than fixing the one you were told about.

Finding index 48 without counting to 48

  • Confirm it is configuration, not conversation. Start a brand-new session and send a one-word prompt. If it fails identically, the tool list is the cause and nothing about your history matters. If it succeeds, you are on the wrong page.
  • Isolate the source with one command. claude --safe-mode starts with all plugins, MCP servers and hooks disabled. If the error disappears there, the offending name comes from one of those and not from a built-in tool. That is a single command replacing an afternoon of guessing.
  • Bring servers back one at a time. Re-enable them individually until the error returns. The server you just enabled owns the name — and, because the prefix is derived from the server name, it is also where the fix goes.
  • Read the names your client actually sends, not the ones you configured. Enable debug logging and look at the assembled tool list in ~/.claude/debug/<session-id>.txt. The name in that log is the string being measured. Every other source — the server’s README, your config file, /mcp — shows you a name without the prefix, which is the name that is not being rejected.
  • Measure every name, not just the reported one. Once you have the assembled list, check all of them against the limit in one pass. A server that generates tool names from an API schema tends to produce several long ones together, so the one you were told about is rarely alone.

Shortening the right half of the name

  • The server is yours. Rename it in the configuration entry to something short, and keep the tool names as they are. Everything the server exposes gets the same relief.
  • The server is third-party. Rename it in your configuration anyway — the server name is a key in your config, not a property of the upstream package. This is the case where people wrongly conclude they are stuck.
  • The tool names themselves are generated and long. If the server supports filtering or aliasing which tools it exposes, cut the list down. Fewer tools is also a smaller request and a shorter list for the model to read, so this is rarely a pure cost.
  • The name is genuinely required at that length. Then the tool cannot be exposed through that server as configured, and the honest options are to wrap it behind a shorter name or to drop it. Nothing on the client side can raise a limit enforced at the API surface.
  • You define tools yourself against the API. Validate the length at the point where you build the tool list, and fail loudly in your own code. A name-length bug caught in a unit test costs a second; caught in production it costs every request until someone reads a 400.

Confirming it clears

Do not test in the session where you were debugging — if servers are still disabled from the isolation step, a success proves only that a disabled server cannot break anything.

Re-enable every server you turned off, start a new session, and send a trivial prompt. Two things have to be true: the request succeeds, and the debug log shows the full tool list assembled, including the server you renamed. Then check the longest assembled name in that log against the limit and leave yourself margin — a name sitting one character under the ceiling will fail again the next time the upstream server adds a slightly longer tool.

Tool trouble that appears mid-conversation rather than on the first request is a different class entirely. If a request starts failing after an interrupt and the message names tool use concurrency and tells you to run /rewind, your stored history is broken rather than your configuration, and the repair is rewind rather than an edit. If the 400 complains that thinking blocks in the latest assistant message were modified, something rewrote a response on its way back — again history, not config. And if it reports an invalid JSON body with a character offset, the request never even parsed, so no field path exists to point at. The quickest discriminator across all of these is the one from the top of this page: does a brand-new session fail on its first message? The AI coding error triage tool starts from exactly that question.