Problem
When a hosted macOS app's agent-device client sends a request that Stim's pinned agent-device relay does not accept, the relay answers HTTP 400 with the plain text Unsupported request. The agent-device client parses every response body as JSON, so the agent sees COMMAND_FAILED "Invalid daemon response" with Unexpected token 'U', "Unsupporte"... is not valid JSON instead of a refusal that says what was refused.
Reproduce: host an app with stim macos --host <machine> (agent driver agent-device), then run agent-device doctor --platform macos --remote-config <file> (or devices, apps).
Expected: a typed refusal like the daemon's own MACOS_APP_LEASE_DENIED (UNAUTHORIZED, a hint, retriable: false, details.reason).
Evidence
Live check 2026-10-05, hosted Desktop on janics-mac-mini, agent-device client from callstack/agent-device#3236. A lease refusal from the daemon arrives as error.code UNAUTHORIZED with details.reason: "MACOS_APP_LEASE_DENIED". A request the relay refuses arrives as COMMAND_FAILED "Invalid daemon response", details.line: "Unsupported request.". The same plain-text refusal was seen for apps and devices in #2477.
Cause
relayPinned in packages/server/src/agent-device-driver.ts writes 400 text/plain Unsupported request. whenever pinLease returns null. pinLease returns null for an unreadable body, a method other than command and lease heartbeat/release, a command outside the policy allow list, and a batch step outside it. The client (daemon-client-rpc.ts) reads the body of any status as a JSON-RPC envelope: { jsonrpc, id, error: { code, message, data: { code, message, hint, details, retriable } } }.
Fix idea
Answer with a JSON-RPC error envelope in the daemon's shape: data.code UNAUTHORIZED, data.details.reason STIM_AGENT_REQUEST_REFUSED, a rule of command, method or request, and a message that names the refused command or method. Keep refusing exactly what is refused today and keep HTTP 400. Echo the request's JSON-RPC id.
Problem
When a hosted macOS app's agent-device client sends a request that Stim's pinned agent-device relay does not accept, the relay answers HTTP 400 with the plain text
Unsupported request.The agent-device client parses every response body as JSON, so the agent seesCOMMAND_FAILED"Invalid daemon response" withUnexpected token 'U', "Unsupporte"... is not valid JSONinstead of a refusal that says what was refused.Reproduce: host an app with
stim macos --host <machine>(agent driveragent-device), then runagent-device doctor --platform macos --remote-config <file>(ordevices,apps).Expected: a typed refusal like the daemon's own
MACOS_APP_LEASE_DENIED(UNAUTHORIZED, a hint,retriable: false,details.reason).Evidence
Live check 2026-10-05, hosted Desktop on janics-mac-mini, agent-device client from callstack/agent-device#3236. A lease refusal from the daemon arrives as
error.code UNAUTHORIZEDwithdetails.reason: "MACOS_APP_LEASE_DENIED". A request the relay refuses arrives asCOMMAND_FAILED"Invalid daemon response",details.line: "Unsupported request.". The same plain-text refusal was seen forappsanddevicesin #2477.Cause
relayPinnedinpackages/server/src/agent-device-driver.tswrites400 text/plainUnsupported request.wheneverpinLeasereturns null.pinLeasereturns null for an unreadable body, a method other than command and lease heartbeat/release, a command outside the policy allow list, and a batch step outside it. The client (daemon-client-rpc.ts) reads the body of any status as a JSON-RPC envelope:{ jsonrpc, id, error: { code, message, data: { code, message, hint, details, retriable } } }.Fix idea
Answer with a JSON-RPC error envelope in the daemon's shape:
data.codeUNAUTHORIZED,data.details.reasonSTIM_AGENT_REQUEST_REFUSED, aruleofcommand,methodorrequest, and a message that names the refused command or method. Keep refusing exactly what is refused today and keep HTTP 400. Echo the request's JSON-RPCid.