MMSP-RFC-0007 Error Types
- Feature Name:
error_types - Start Date: 2026-10-24
- RFC PR: #301
- Kind: spec
Abstract
Outside integration/, every error MMSP raises, apart from the abort error, is an MMSPError subclass from errors.py / errors.ts, named for what went wrong and carrying its fields. This document specifies the classes, where each is raised, the built-ins they are, how the MMSP server relays them, and how a class is added.
1. Introduction
A caller that handles a refusal needs one class to catch, the same in both packages and through the server; a bare ValueError or Error cannot be told from a bug. The audit that wrote the first rule found tts_config rejected with a bare error in both Google clients (#269). The audit of 2026-10-23 found about sixty more places, from a tool result without its tool_call_id to an image on a text-only model, and the owner widened the rule from a rejected value to every error (#288, #290). Stated in #265 as MMSP-RFC-0007 and in #298 as MMSP-RFC-0009.
2. Conventions and Terminology
The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this document are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174) when, and only when, they appear in all capitals.
- Bare built-in error: an instance of a built-in class itself, such as
ValueError,RuntimeErrororError, rather than of anMMSPErrorsubclass. - Abort error:
asyncio.CancelledErrorcarrying the signal's reason in Python, the signal'sreasonin TypeScript (MMSP-RFC-0008 §2).
3. The Error Classes
Code outside integration/ MUST NOT raise or throw a bare built-in error of its own: apart from the abort error, what it raises is one of the classes below. An exception it only passes on, such as a vendor SDK's or a cancellation of the caller's task, propagates as it is.
3.1 Before the request
UnsupportedParameterError: aUniConfigvalue the model cannot take, naming the client and the parameter.thinking_levelMUST NOT be one (MMSP-RFC-0003 §6.3).UnsupportedContentError: a well-formed item the model cannot take.InvalidMessageError: a message that cannot be sent as it is, withitem_typeandmessage_indexwhere they apply, such as an unknown item, a tool result withouttool_call_id, an image that is not valid base64, a TTS script without speaker labels, or a message with nothing to send.UnsupportedOperationError: an operation a client cannot perform at all.ConcurrentCallError(MMSP-RFC-0004 §6.2);RoutingError(MMSP-RFC-0005 §4);ApiKeyRequiredError, from the constructor (MMSP-RFC-0006 §4).
3.2 Inside a stream
In place of the item or the stop (MMSP-RFC-0003 §5):
ToolCallArgumentParseError: streamed tool call arguments that do not parse as a JSON object;EmptyResponseError: a response with no item but thinking, or with no item at all;IncompleteStreamError: a stream that ended without its usage or its finish reason;StreamProtocolError: a client that broke the stream grammar;ProviderStreamError: an error a provider reports inside an open stream that its SDK does not raise, the Interactions API'serrorevent;UnknownEventError: an unrecognized event underMMSP_DEBUG(MMSP-RFC-0003 §4.1).
3.3 Built-in bases
Every class MUST be a ValueError in Python and an Error in TypeScript, and ProviderStreamError also a RuntimeError in Python.
4. Relay Through the Server
The MMSP server MUST relay every MMSP error with its fields (to_wire_error / toWireError), so the mmsp client raises UpstreamError whose error_type is the class and whose error holds the fields. A vendor SDK's own exception propagates as it is, and the server relays it by its class name, with the upstream's HTTP status where the SDK keeps one.
5. Adding a Class
A new class MUST join to_wire_error / toWireError and the exports of both packages in the same change.
6. Conformance
src_py/mmsp/errors.py,src_ts/src/errors.ts;src_py/mmsp/wire.py/src_ts/src/wire.ts.src_py/tests/test_mmsp_server.py/src_ts/tests/mmsp-server.test.ts, which relay everyMMSPErrorsubclass through the server, check that the cases cover every classerrorsdefines, and check that every class is exported and is the built-in of §3.3.test_stream_protocol.py,test_message_order.py,test_unknown_events.py,test_empty_response.py,test_env_credentials.py,test_image_detail.py,test_client.py,test_list_models.pyand their Jest mirrors, which assert the class at each kind of site.- Review with two greps, which find nothing outside
integration/:grep -rnE "raise (ValueError|RuntimeError|NotImplementedError|TypeError|KeyError|Exception)\b" src_py/mmspandgrep -rnE "throw new (Error|TypeError|RangeError)\b" src_ts/src.