Skip to content

Hosted agent relay refusals reach agent-device as "Invalid daemon response" #2574

Description

@janicduplessis

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions