[Schema] Omit the id of an error response that never had one (#442)

* [Schema] Omit the id of an error response that never had one

An error response whose id could not be read sent `"id": ""`, which claims
the peer issued a request with an empty-string id - a different statement
from "the id could not be read". JSON-RPC spells the latter as a null id,
and a receiver that cannot read the id is exactly the case the code covers.

[BC Break] Error::$id accepts null and getId() may return it. All the for*()
factories default to null, fromArray() accepts a missing or explicitly-null
id, and the member is omitted from the serialized form when absent.

* Guard null response id in Client/Server Protocol handlers

Also fix Error::jsonSerialize()'s phpdoc: data belongs inside error, not beside it.
This commit is contained in:
Christopher Hertel 2026-08-18 15:24:19 +02:00 • committed by GitHub
commit 5041caf77a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -82,6 +82,30 @@ final class ProtocolTest extends TestCase
);
}
#[TestDox('An id-less error response from the client is logged and ignored, not stored under a collapsed session key')]
public function testIdLessErrorResponseIsIgnored(): void
{
$session = $this->createMock(SessionInterface::class);
$session->expects($this->never())->method('set');
$this->sessionManager->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$protocol = new Protocol(
requestHandlers: [],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
$protocol->processInput(
$this->transport,
'{"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}}',
$sessionId
);
}
#[TestDox('A single request is handled only by the first matching handler')]
public function testRequestHandledByFirstMatchingHandler(): void
{