{"record":{"id":"b50786b4a989225c","repo":"github/copilot-sdk","slug":"missing-required-field-message-in-stoperror","errorCode":null,"errorMessage":"Missing required field 'message' in StopError","messagePattern":"Missing required field 'message' in StopError","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/copilot/client.py","lineNumber":882,"sourceCode":"        result[\"protocolVersion\"] = self.protocol_version\n        return result\n\n\n@dataclass\nclass StopError(Exception):\n    \"\"\"Error that occurred during client stop cleanup.\"\"\"\n\n    message: str  # Error message describing what failed during cleanup\n\n    def __post_init__(self) -> None:\n        Exception.__init__(self, self.message)\n\n    @staticmethod\n    def from_dict(obj: Any) -> StopError:\n        assert isinstance(obj, dict)\n        message = obj.get(\"message\")\n        if message is None:\n            raise ValueError(\"Missing required field 'message' in StopError\")\n        return StopError(str(message))\n\n    def to_dict(self) -> dict:\n        result: dict = {}\n        result[\"message\"] = self.message\n        return result\n\n\n@dataclass\nclass GetStatusResponse:\n    \"\"\"Response from status.get\"\"\"\n\n    version: str  # Package version (e.g., \"1.0.0\")\n    protocol_version: int  # Protocol version for SDK compatibility\n\n    @staticmethod\n    def from_dict(obj: Any) -> GetStatusResponse:\n        assert isinstance(obj, dict)","sourceCodeStart":864,"sourceCodeEnd":900,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/client.py#L864-L900","documentation":"StopError.from_dict requires the 'message' key in the stop-error payload; when absent it raises ValueError. The library treats 'message' as the mandatory human-readable error text and refuses to construct a StopError without it.","triggerScenarios":"A stop/error event from the server arrives as a dict without a 'message' field, e.g. {'code': 500} or {'error': '...'} shape instead of the expected flat {'message': '...'} shape.","commonSituations":"Server emitting a differently shaped error object after an upgrade; test fakes returning partial payloads; relaying an underlying error object directly instead of mapping it to the expected schema.","solutions":["Update/align the server or event producer to include 'message' in StopError payloads","Remap the payload in an adapter: if 'message' missing, derive it from 'error'/'detail' before calling from_dict","Fix mocks in tests to include {'message': ...}"],"exampleFix":"// before\nStopError.from_dict({\"error\": \"session stopped\"})\n// after\npayload = {\"error\": \"session stopped\"}\nStopError.from_dict({\"message\": payload.get(\"message\") or payload[\"error\"]})","handlingStrategy":"type-guard","validationCode":"def has_stop_error_message(obj) -> bool:\n    return isinstance(obj, dict) and obj.get(\"message\") is not None","typeGuard":"def is_stop_error_payload(obj: object) -> bool:\n    return isinstance(obj, dict) and isinstance(obj.get(\"message\"), str)","tryCatchPattern":"try:\n    err = StopError.from_dict(payload)\nexcept ValueError as e:\n    if \"Missing required field 'message'\" in str(e):\n        err = StopError(str(payload.get(\"error\", payload)))\n    else:\n        raise","preventionTips":["Map upstream error shapes to the library's flat {'message': ...} schema before decoding","Keep fixtures aligned with the real server error payloads","Cover from_dict paths in tests with schema-compliant payloads"],"tags":["python","deserialization","stop-error","schema"],"backgroundTag":"missing-required-argument","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}