different-ai/openwork · error · SafeProbeFailure
invalid_jsonrpc_envelope
invalid_jsonrpc_envelope
Error message
invalid_jsonrpc_envelope
What it means
parseJsonRpcResult validates the decoded JSON-RPC payload envelope and throws SafeProbeFailure("invalid_jsonrpc_envelope") at line 529 when the payload is not an object or its 'jsonrpc' field is not exactly "2.0". The probe only accepts well-formed JSON-RPC 2.0 responses. A second throw of the same code (line 533) fires when 'result' is missing or not an object.
Source
Thrown at apps/server/src/agent-context-cloud-probe.ts:529
dispatch();
continue;
}
if (line.startsWith(":")) continue;
const colon = line.indexOf(":");
const field = colon < 0 ? line : line.slice(0, colon);
const rawValue = colon < 0 ? "" : line.slice(colon + 1);
const value = rawValue.startsWith(" ") ? rawValue.slice(1) : rawValue;
if (field === "event") event = value;
if (field === "data") data.push(value);
}
dispatch();
if (messages.length !== 1) throw new SafeProbeFailure("invalid_json");
return messages[0];
}
function parseJsonRpcResult(payload: unknown, requestId: string): Record<string, unknown> {
if (!isRecord(payload) || payload.jsonrpc !== "2.0") {
throw new SafeProbeFailure("invalid_jsonrpc_envelope");
}
if (Object.hasOwn(payload, "error")) throw new SafeProbeFailure("jsonrpc_error");
if (payload.id !== requestId) throw new SafeProbeFailure("request_id_mismatch");
if (!isRecord(payload.result)) throw new SafeProbeFailure("invalid_jsonrpc_envelope");
return payload.result;
}
function requireSupportedProtocolVersion(initializeResult: Record<string, unknown>): void {
const version = initializeResult.protocolVersion;
if (typeof version !== "string" || version.length === 0 || version.length > MAX_PROTOCOL_HEADER_LENGTH) {
throw new SafeProbeFailure("invalid_jsonrpc_envelope");
}
if (version !== MCP_PROTOCOL_VERSION) throw new SafeProbeFailure("unsupported_protocol_version");
}
function validateCatalog(rpcResult: Record<string, unknown>): { toolIds: string[]; totalToolCount: number } {
if (rpcResult.nextCursor !== undefined && rpcResult.nextCursor !== null) {
throw new SafeProbeFailure("pagination_unsupported");View on GitHub (pinned to 2b7df46e8a)
Solutions
- Confirm the probe URL points at the MCP endpoint that speaks JSON-RPC 2.0
- Make the server include "jsonrpc":"2.0" in every response
- Inspect the raw response body to see what the server actually returned
- Check for a reverse proxy serving an error/config page at that path
Example fix
// before
{"id":1,"result":{...}}
// after
{"jsonrpc":"2.0","id":1,"result":{...}} Defensive patterns
Strategy: type-guard
Validate before calling
const body = JSON.parse(raw);
if (typeof body !== "object" || body === null || (body as Record<string, unknown>).jsonrpc !== "2.0") {
throw new Error("endpoint response is not JSON-RPC 2.0");
} Type guard
function isJsonRpc2Envelope(v: unknown): v is { jsonrpc: "2.0"; id: unknown } & Record<string, unknown> {
return typeof v === "object" && v !== null && (v as Record<string, unknown>).jsonrpc === "2.0";
} Try / catch
try {
const result = parseJsonRpcResult(payload, requestId);
} catch (e) {
if (e instanceof SafeProbeFailure && e.code === "invalid_jsonrpc_envelope") {
console.error("endpoint did not return a JSON-RPC 2.0 envelope", rawBody);
} else throw e;
} Prevention
- Pin probe URLs to verified MCP endpoints and version them in config
- Smoke-test the endpoint with a raw JSON-RPC 2.0 initialize call before wiring it in
- Add a contract test asserting the jsonrpc:"2.0" field on all server responses
When it happens
Trigger: Endpoint returns a JSON body that is not an object (array/string/number/null), or an object whose jsonrpc field is absent or not "2.0".
Common situations: Hitting a non-MCP REST endpoint at the probe URL; server implements an older/different JSON-RPC dialect (e.g. jsonrpc "1.0" or omitted field); a gateway error page returning JSON but not JSON-RPC.
Related errors
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/9feab5f293ab2e3f.
Report an issue: GitHub.