[Schema][Server] Preserve request id in JSON-RPC error responses instead of fabricating id:"" (#379)

* Preserve request id in JSON-RPC error responses instead of fabricating id:""

When the server received input it could not turn into a valid message, the
error response carried a fabricated empty-string id that was never in the
request, breaking JSON-RPC client correlation.

The id default for the error factories was '' and that default reached the
wire unchanged: unrecoverable parse errors emitted id:"", and for invalid-
but-parseable messages MessageFactory discarded the decoded id so it also
fell back to "".

Now unrecoverable parse errors (-32700) return id: null per JSON-RPC 2.0,
and invalid-but-parseable requests (-32600) preserve the original request
id. Error::$id / getId() and the $id parameter of forParseError() /
forInvalidRequest() are widened to string|int|null, and the recoverable id
is threaded through InvalidInputMessageException.

Fixes #333

* Preserve nullable request id consistently across Error factories and fromArray

- Widen the remaining for*() factories (forMethodNotFound, forInvalidParams,
  forInternalError, forServerError, forResourceNotFound) to string|int|null
  defaulting to null, so no error path can fabricate id:"" again. The only
  defaulting call site (ProtocolVersionMiddleware) now emits id:null instead
  of id:"" for a pre-parse rejection, which is the spec-correct value.
- Accept a null id in Error::fromArray(): require the id key to be present
  (JSON-RPC responses must carry it) but allow its value to be null, so a
  spec-compliant id:null error response round-trips and incoming error
  responses with id:null are accepted instead of rejected.
- Widen the @phpstan-type ErrorData id to string|int|null to match the ctor,
  getId(), and jsonSerialize() shape.

* Document intentional id recovery guard in MessageFactory

* Cover id: 0 and string ids in recoverable-id preservation test

* Fixed client handling of null-id error responses
This commit is contained in:
Valeriu Gutu 2026-08-18 16:47:27 +03:00 • committed by GitHub
commit 1961414432
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -228,7 +228,7 @@ class Protocol
{
$this->logger->warning('Failed to create message.', ['exception' => $exception]);
$error = Error::forInvalidRequest($exception->getMessage());
$error = Error::forInvalidRequest($exception->getMessage(), $exception->getRequestId());
$this->sendResponse($transport, $error, $session);
}