paperclipai/paperclip · error
${provider} inventory failed: ${message}
Error message
${provider} inventory failed: ${message} What it means
Thrown by jsonResponse when the provider responds with a non-OK HTTP status (response.ok is false). The helper extracts the provider's 'message' field from the JSON body when present, otherwise falls back to the numeric status, and wraps it as '<provider> inventory failed: <message>'. This is the generic upstream-API-error path for GitHub/Slack inventory calls.
Source
Thrown at server/src/services/chat-provider-inventory.ts:56
return AbortSignal.timeout(GITHUB_API_TIMEOUT_MS);
}
async function jsonResponse<T>(
response: Response,
provider: string,
): Promise<T> {
let body: unknown;
try {
body = await response.json();
} catch {
throw new Error(`${provider} returned an unreadable inventory response`);
}
if (!response.ok) {
const message =
body && typeof body === "object" && "message" in body
? String((body as { message?: unknown }).message)
: String(response.status);
throw new Error(`${provider} inventory failed: ${message}`);
}
return body as T;
}
/** List only Slack conversations where the installed bot is a member. */
export async function listSlackBotChannels(input: {
botToken: string;
fetch: typeof globalThis.fetch;
}): Promise<ChatProviderInventoryResult> {
const resources: ChatProviderResourceInventoryItem[] = [];
let cursor = "";
do {
const url = new URL("https://slack.com/api/conversations.list");
url.searchParams.set("types", "public_channel,private_channel");
url.searchParams.set("exclude_archived", "true");
url.searchParams.set("limit", "200");
if (cursor) url.searchParams.set("cursor", cursor);
const response = await input.fetch(url, {View on GitHub (pinned to 01ad858492)
Solutions
- Read the embedded message: fix the specific cause (refresh token, add scopes, back off).
- If 401/403, reconnect the chat connection to obtain fresh tokens/scopes.
- If 429, implement/respect exponential backoff using Retry-After headers.
- Check provider status pages and retry on 5xx.
- Verify the account/app has not been deactivated or suspended.
Defensive patterns
Strategy: try-catch
Try / catch
try { const inv = await listProviderResources(input); }
catch (e) {
const msg = e.message; // '<Provider> inventory failed: <detail>'
if (msg.includes('429') || /rate/i.test(msg)) await backoffAndRetry();
else if (/401|403|token|scope/i.test(msg)) await promptReconnect();
else throw e;
} Prevention
- Refresh provider tokens before expiry (Slack bot tokens, GitHub installation tokens).
- Request all required scopes at install time to avoid 403s.
- Throttle inventory scans and honor Retry-After on 429.
- Alert on provider 5xx and retry with exponential backoff.
When it happens
Trigger: Any 4xx/5xx from the provider during inventory: 401 invalid/expired token, 403 missing scopes or suspended app, 404 wrong resource/endpoint, 429 rate limited, 5xx provider outage.
Common situations: Expired or revoked Slack bot token / GitHub installation token; insufficient scopes after reinstall; hitting Slack/GitHub rate limits during large inventory scans; provider incident.
Related errors
- GitHub could not update this App's webhook (HTTP ${response.
- Slack inventory failed: ${body.error ?? "unknown error"}
- GitHub inventory failed: installation token was missing
- GitHub inventory failed: install this GitHub App on the sele
- GitHub inventory failed: this chat connection requires a ded
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/cb06569c5c2c0e56.
Report an issue: GitHub.