ruvnet/ruflo · error · Error

--token-stdin expects a single JSON object: {"access_token",

Error message

--token-stdin expects a single JSON object: {"access_token","refresh_token"?,"expires_in","scope"}

What it means

Thrown by tokenStdinLogin when stdin had content but it was not valid JSON. --token-stdin requires a single JSON object, not a bare token string or other text.

Source

Thrown at v3/@claude-flow/cli/src/auth/client.ts:187

}

/**
 * `--token-stdin`: reads one JSON object from stdin,
 * `{access_token, refresh_token?, expires_in, scope}`. Wire format is not
 * specified by ADR-306 — defined here as typed JSON rather than a bare
 * token string, so scope/expiry are explicit rather than inferred.
 */
export async function tokenStdinLogin(input: NodeJS.ReadableStream = process.stdin): Promise<LoginResult> {
  const chunks: Buffer[] = [];
  for await (const chunk of input) chunks.push(chunk as Buffer);
  const raw = Buffer.concat(chunks).toString('utf-8').trim();
  if (!raw) throw new Error('--token-stdin: no input received on stdin');

  let parsed: { access_token?: string; refresh_token?: string; expires_in?: number; scope?: string };
  try {
    parsed = JSON.parse(raw);
  } catch {
    throw new Error(
      '--token-stdin expects a single JSON object: {"access_token","refresh_token"?,"expires_in","scope"}',
    );
  }
  if (!parsed.access_token) throw new Error('--token-stdin: JSON is missing required field "access_token"');

  const tokens: OAuthTokenResponse = {
    access_token: parsed.access_token,
    token_type: 'Bearer',
    refresh_token: parsed.refresh_token,
    expires_in: parsed.expires_in,
  };
  return { tokens, method: 'token-stdin' };
}

/**
 * Refreshes an access token. Classifies failure into network-unreachable
 * vs. a reachable-but-erroring server so callers can print an honest
 * message instead of collapsing both into "offline" (ADR-308 failure

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Wrap the token as JSON: {"access_token":"...","expires_in":3600,"scope":"..."}.
  2. Validate that the producer emits the documented JSON wire format.

Example fix

# before
echo "$ACCESS_TOKEN" | ruflo auth login --token-stdin

# after
jq -n --arg t "$ACCESS_TOKEN" '{access_token:$t,expires_in:3600,scope:"default"}' | ruflo auth login --token-stdin
Defensive patterns

Strategy: validation

Validate before calling

let parsed: unknown;
try {
  parsed = JSON.parse(raw);
} catch {
  throw new Error('stdin is not JSON; wrap as {"access_token":...,"expires_in":...,"scope":...}');
}

Type guard

function isTokenObject(v: unknown): v is { access_token: string } {
  return !!v && typeof v === 'object' && typeof (v as { access_token?: unknown }).access_token === 'string';
}

Prevention

When it happens

Trigger: Piping a bare access token string, a raw JWT, YAML, or any non-JSON text to --token-stdin.

Common situations: User assumed --token-stdin takes a bare token; producer emitted a different format than the JSON wire shape.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/65fe7a7078ea5430. Report an issue: GitHub.