hcengineering/platform · warning · PlatformError
platform.status.BadRequest
platform.status.BadRequest
Error message
BadRequest
What it means
readRequest deserializes an incoming RPC payload with protoDeserialize (JSON or msgpack) and then validates that the decoded object has a string `method` field. If the payload decodes to something without a string method — garbage bytes, wrong encoding, or a non-RPC body — the server rejects it with a PlatformError carrying platform.status.BadRequest. It is a protocol-level guard against malformed client requests.
Source
Thrown at foundations/core/packages/rpc/src/rpc.ts:202
* @returns
*/
readResponse<D>(response: any, binary: boolean): Response<D> {
const data = this.protoDeserialize(response, binary)
if (data.result !== undefined) {
data.result = rpcJSONReceiver('result', data.result)
}
return data
}
/**
* @public
* @param request -
* @returns
*/
readRequest<P extends any[]>(request: any, binary: boolean): Request<P> {
const result: Request<P> = this.protoDeserialize(request, binary)
if (typeof result.method !== 'string') {
throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {}))
}
return result
}
}
/**
* @public
* @param status -
* @param id -
* @returns
*/
export function fromStatus (status: Status, id?: ReqId): Response<any> {
return { id, error: status }
}
View on GitHub (pinned to 63e28dc964)
Solutions
- Log the raw payload and the binary flag on the server just before readRequest to see what actually arrived.
- Verify the client serializes with the same format/protocol version as the server expects (binary vs JSON) and that both use the same @hcengineering/rpc version.
- If testing manually, send a full RPC Request object, e.g. {id:1, method:'methodName', params:[...]}.
- Check any intermediate proxy/gateway is not stripping or re-encoding the request body.
Example fix
// before: hand-crafted payload posted to the RPC endpoint
fetch(rpcUrl, { method: 'POST', body: JSON.stringify({ method: 'hello' }) }) // missing id/params, or wrong encoding
// after: use the client-side serializer so the shape matches
const payload = RPC.serialize({ id: 1, method: 'hello', params: [] }, binary)
await send(payload) Defensive patterns
Strategy: try-catch
Validate before calling
// client-side: confirm the payload decodes to a Request with a string method before sending
function isRpcRequest (p: unknown): boolean {
return typeof p === 'object' && p !== null && typeof (p as any).method === 'string'
}
if (!isRpcRequest(myPayload)) throw new TypeError('Not a valid RPC request payload') Type guard
function isRequest<P extends any[]> (v: unknown): v is { id: string, method: string, params: P } {
return typeof v === 'object' && v !== null && typeof (v as any).method === 'string' && Array.isArray((v as any).params)
} Try / catch
try {
const req = rpc.readRequest(payload, binary)
// handle
} catch (err) {
if (err instanceof PlatformError && err.status.code === platform.status.BadRequest) {
// log raw payload + binary flag, respond 400
} else throw err
} Prevention
- Always build requests through the library's serialize() path, never hand-rolled JSON.
- Keep @hcengineering/rpc versions identical on client and server.
- Verify the binary flag matches the transport framing on both ends.
- Add a debug log of the raw payload when BadRequest occurs.
When it happens
Trigger: Server calls readRequest (via request/cs) on a payload where protoDeserialize yields an object whose `method` is not a string: non-RPC data sent to the RPC endpoint, JSON payload decoded when the client actually sent msgpack (binary flag mismatch), truncated/corrupted frames, or a raw HTTP client posting arbitrary JSON without a `method` field.
Common situations: Client and server built from different package versions with different serialization defaults (JSON vs msgpack); a proxy/worker re-encoding the body; curl/Postman tests hitting the RPC endpoint with plain JSON like {"id":1} but no `method`; a WebSocket client speaking the wrong protocol revision.
Related errors
- Unknown method${method}
- platform.status.ConnectionClosed
- HTTP error ${res.status}
- result.error
- Token type `${node.type}` not supported by Markdown renderer
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/8e13d3e94c2b8423.
Report an issue: GitHub.