different-ai/openwork · error · DenApiError
invalid_mcp_token_payload
invalid_mcp_token_payload
Error message
MCP token response was missing required values.
What it means
mintMcpToken POSTs to /v1/mcp/token requesting mcp:read and mcp:write scopes, then parses the payload with parseDenMcpToken. If the response is missing required token values, a 500 DenApiError with code "invalid_mcp_token_payload" is thrown so callers never receive a partially-formed MCP token.
Source
Thrown at apps/app/src/app/lib/den.ts:3100
});
// 404 means the memory is already gone (or not owned) — idempotent from the caller's view.
if (!result.ok && result.status !== 404) {
const payload = result.json;
const code = isRecord(payload) && typeof payload.error === "string" ? payload.error : "request_failed";
throw new DenApiError(result.status, code, getErrorMessage(payload, `Delete failed with ${result.status}.`));
}
},
async mintMcpToken(orgId: string): Promise<DenMcpToken> {
const payload = await requestJson<unknown>(baseUrls, "/v1/mcp/token", {
method: "POST",
token,
organizationId: orgId,
body: { scopes: ["mcp:read", "mcp:write"] },
});
const minted = parseDenMcpToken(payload);
if (!minted) {
throw new DenApiError(500, "invalid_mcp_token_payload", "MCP token response was missing required values.");
}
return minted;
},
async getWorkerTokens(workerId: string, orgId: string): Promise<DenWorkerTokens> {
const payload = await requestJson<unknown>(baseUrls, `/v1/workers/${encodeURIComponent(workerId)}/tokens`, {
method: "POST",
token,
organizationId: orgId,
body: {},
});
const tokens = getWorkerTokens(payload);
if (!tokens) {
throw new DenApiError(500, "invalid_worker_token_payload", "Worker token response was missing token values.");
}
return tokens;
},
View on GitHub (pinned to 2b7df46e8a)
Solutions
- Verify the Den server version supports MCP token minting with the expected response shape
- Log the raw payload to identify the missing field
- Re-authenticate and retry if the failure could be session-related
- Fix baseUrl/proxy configuration so the real Den server responds
Example fix
// before
const token = await client.mintMcpToken(orgId);
connectMcp(token);
// after
try { connectMcp(await client.mintMcpToken(orgId)); }
catch (err) {
if (err instanceof DenApiError && err.code === "invalid_mcp_token_payload") throw new Error("MCP token unavailable on this Den server");
throw err;
} Defensive patterns
Strategy: type-guard
Validate before calling
if (!orgId) throw new Error("An organization id is required to mint an MCP token"); Type guard
const isDenMcpToken = (t: unknown): t is DenMcpToken =>
typeof t === "object" && t !== null && "token" in t && typeof (t as { token: unknown }).token === "string" && (t as { token: string }).token.length > 0; Try / catch
try {
mcpToken = await client.mintMcpToken(orgId);
} catch (err) {
if (err instanceof DenApiError && err.code === "invalid_mcp_token_payload") {
throw new Error("This Den server cannot mint MCP tokens; upgrade the server");
} else throw err;
} Prevention
- Confirm the Den server supports MCP token minting before wiring the flow
- Validate the minted token is a non-empty string before storing it
- Re-mint rather than cache tokens across sessions
When it happens
Trigger: The mint endpoint returns 2xx but the body lacks the expected token fields — server schema drift, wrong server, or a proxy altering the response.
Common situations: Self-hosted Den version without full MCP token support, server-side minting failure swallowed into a 2xx, or misconfigured baseUrl.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- invalid_session_payload
- invalid_app_version_payload
- invalid_resource_snapshot_payload
- invalid_worker_token_payload
- MCP tool catalog response was incomplete.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/baa0cc4b282a9781.
Report an issue: GitHub.