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

  1. Log the raw payload and the binary flag on the server just before readRequest to see what actually arrived.
  2. 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.
  3. If testing manually, send a full RPC Request object, e.g. {id:1, method:'methodName', params:[...]}.
  4. 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

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


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/8e13d3e94c2b8423. Report an issue: GitHub.