paperclipai/paperclip · error · ServeParseError

serve status must be a JSON object

Error message

serve status must be a JSON object

What it means

Top-level shape guard in parseServeStatus, which parses `tailscale serve status` JSON: the decoded value is not a JSON object (array, string, null, etc.). Nothing downstream can be read, so parsing fails before TCP/Web normalization.

Source

Thrown at packages/tailscale-https-broker/src/serve-config.ts:60

  const idx = key.lastIndexOf(":");
  if (idx <= 0 || idx === key.length - 1) {
    throw new ServeParseError(`malformed Web key: ${JSON.stringify(key)}`);
  }
  const portText = key.slice(idx + 1);
  if (!/^[0-9]+$/.test(portText)) {
    throw new ServeParseError(`non-numeric port in Web key: ${JSON.stringify(key)}`);
  }
  return assertCanonicalPort(Number(portText));
}

/**
 * Parse serve status JSON into a normalized, port-keyed model. Tolerates extra
 * top-level fields (Tailscale evolves its schema) but strictly validates the
 * `TCP` and `Web` shapes it depends on.
 */
export function parseServeStatus(json: unknown): ParsedServe {
  if (!isObject(json)) {
    throw new ServeParseError("serve status must be a JSON object");
  }
  const entries = new Map<number, ServeEntry>();

  const tcp = json.TCP;
  const httpsPorts = new Set<number>();
  if (tcp !== undefined && tcp !== null) {
    if (!isObject(tcp)) throw new ServeParseError("TCP must be an object");
    for (const [portKey, value] of Object.entries(tcp)) {
      if (!/^[0-9]+$/.test(portKey)) {
        throw new ServeParseError(`non-numeric TCP port: ${portKey}`);
      }
      const port = assertCanonicalPort(Number(portKey));
      if (!isObject(value)) throw new ServeParseError(`TCP[${portKey}] must be an object`);
      if (value.HTTPS === true) httpsPorts.add(port);
      if (!entries.has(port)) entries.set(port, { port, https: value.HTTPS === true, handlers: [] });
      else entries.get(port)!.https = value.HTTPS === true;
    }
  }

View on GitHub (pinned to 120ae5428f)

Solutions

  1. Ensure `tailscale serve status --json` returns a JSON object; check the tailscale version and command output.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/tailscale-https-broker/src/serve-config.ts:60 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18). Data as JSON: /api/errors/67e3d9a1a62bef80. Report an issue: GitHub.