paperclipai/paperclip · error

Anthropic did not return usable Agent and Environment identi

Error message

Anthropic did not return usable Agent and Environment identities

What it means

setupManagedAgent resolves the Agent and Environment in parallel and coerces both `id` fields to strings; if either is empty the Anthropic API returned a resource without a usable identity. Throwing here prevents writing credentials/config based on malformed responses rather than failing later with obscure 404s.

Source

Thrown at cli/src/commands/managed-agent.ts:339

  const validated = validateManagedAgentSetup(options);
  const normalizedOptions: ManagedAgentSetupOptions = {
    ...options,
    profileKey: validated.profileKey,
    displayName: validated.displayName,
    apiKeySecretId: validated.apiKeySecretId,
    model: validated.model,
    agentId: validated.agentId,
    agentVersion: validated.agentVersion,
    environmentId: validated.environmentId,
  };
  const [environment, agent] = await Promise.all([
    resolveEnvironment(validated.anthropicApiKey, normalizedOptions),
    resolveAgent(validated.anthropicApiKey, normalizedOptions),
  ]);
  const agentId = String(agent.id ?? "");
  const environmentId = String(environment.id ?? "");
  if (!agentId || !environmentId) {
    throw new Error("Anthropic did not return usable Agent and Environment identities");
  }

  const versions = await listAll(
    validated.anthropicApiKey,
    `/v1/agents/${encodeURIComponent(agentId)}/versions`,
  );
  const version = normalizedOptions.agentVersion
    ?? String(agent.version ?? versions.at(-1)?.version ?? "");
  const pinnedAgent = version
    ? versions.find((entry) => String(entry.version) === version)
    : undefined;
  if (!version || !pinnedAgent) {
    throw new Error("Anthropic did not return a usable pinned Agent version");
  }
  if (String(pinnedAgent.id ?? "") !== agentId) {
    throw new Error("Anthropic pinned Agent version identity does not match the selected Agent");
  }
  assertSafeManagedAgent(pinnedAgent);

View on GitHub (pinned to 5716fe907e)

Solutions

  1. Log the raw JSON responses of /v1/environments and /v1/agents to see which resource lacks `id`.
  2. Check the Anthropic API version / changelog for identity-field changes and pin a supported api-version header.
  3. Retry after ruling out transient gateway interference (direct curl to api.anthropic.com).
  4. Update the Paperclip CLI to the latest version if Anthropic changed the response shape.

Example fix

// before: blindly trusting the API shape
const agent = await anthropicRequest(key, "POST", "/v1/agents", body);
// after: like the library, validate before use
const agentId = String(agent.id ?? "");
if (!agentId) throw new Error("Anthropic did not return a usable Agent id");
Defensive patterns

Strategy: type-guard

Validate before calling

// validate the API response shape before consuming it
function hasUsableId(r: unknown): r is { id: string | { id: string } } {
  return typeof r === "object" && r !== null && (typeof (r as any).id === "string" || typeof (r as any).id?.id === "string");
}
const agent = await anthropicRequest(key, "POST", "/v1/agents", body);
if (!hasUsableId(agent)) throw new Error("Anthropic agent response missing id");

Type guard

function hasStringId(v: unknown): v is { id: string } {
  return typeof v === "object" && v !== null && typeof (v as { id?: unknown }).id === "string" && (v as { id: string }).id.length > 0;
}

Try / catch

try {
  await setupManagedAgent(options);
} catch (e) {
  if (e instanceof Error && e.message.includes("usable Agent and Environment identities")) {
    // capture raw responses for diagnosis, then retry or report API drift
    const raw = await anthropicRequest(key, "GET", "/v1/agents");
    console.error("Unexpected API shape:", JSON.stringify(raw).slice(0, 500));
  }
  throw e;
}

Prevention

When it happens

Trigger: POST/GET responses from /v1/environments or /v1/agents missing an `id` field — e.g. API contract change, an error-shaped body that still parsed as an object, or a proxy/gateway returning unexpected JSON.

Common situations: Anthropic API version drift where ids moved to a different field; a corporate proxy stripping or reshaping response bodies; using a stubbed/mock endpoint that omits ids; transient partial responses.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@5716fe907e (2026-09-02). Data as JSON: /api/errors/aeaad39ec2cdee43. Report an issue: GitHub.