gitroomhq/postiz-app · error · HttpException
Unexpected error
Error message
Unexpected error
What it means
triggerIntegrationTool wraps tool invocation in a while(true) loop with a 10-second timer between attempts; if every attempt falls through the retry branches without producing a success or early throw, the loop exits to a catch-all 500 'Unexpected error'. It signals an unclassifiable provider-side failure that persisted through all retries.
Source
Thrown at apps/backend/src/public-api/routes/v1/public.integrations.controller.ts:631
throw new HttpException(
{ msg: 'Channel disconnected due to expired token' },
401
);
}
const { accessToken } = data;
if (accessToken) {
getIntegration.token = accessToken;
if (integrationProvider.refreshWait) {
await timer(10000);
}
continue;
}
}
throw new HttpException({ msg: 'Unexpected error' }, 500);
}
}
}
}
View on GitHub (pinned to 0f1647f749)
Solutions
- Inspect the backend logs at the time of the 500 to see the underlying provider exception and response payload
- Test the same tool invocation from the UI to isolate whether it is specific to the public API call's arguments
- Verify the arguments match the tool's expected schema (many tools fail silently on malformed input)
- If the channel's API changed, update Postiz to a version with the fixed provider implementation
Example fix
// before
const res = await triggerTool(id, method, args); // throws 500 'Unexpected error'
// after
// capture and log the tool response/args to identify the provider-level failure
try {
const res = await triggerTool(id, method, args);
} catch (e) {
if (e.status === 500) {
logger.error('tool failed', { id, method, args, body: e.response?.body });
// inspect backend logs for the underlying provider error
}
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
if (!body?.methodName || typeof body.methodName !== 'string') throw new Error('methodName required');
// validate args against the tool's documented schema before calling Type guard
const isUnexpectedToolError = (e: unknown): boolean => (e as any)?.status === 500 && (e as any)?.response?.msg === 'Unexpected error';
Try / catch
try {
await triggerTool(id, method, args);
} catch (e: any) {
if (e?.status === 500) {
await sleep(5000);
return triggerTool(id, method, args); // single client-side retry; server already retried internally
}
throw e;
} Prevention
- Log full tool args and correlation ids with each 500 for backend-log correlation
- Snapshot provider API response shapes in tests to catch schema drift early
- Keep backend updated so provider fixes for upstream API changes are picked up
When it happens
Trigger: POST to triggerIntegrationTool where the provider method keeps returning a falsy/unknown result shape (neither success nor a recognized retry condition) until the internal retry budget is exhausted; also any unexpected exception from the dynamic integrationProvider[body.methodName] call that is not caught by the token-refresh branch.
Common situations: Provider API returning an unexpected response schema (breaking change on the channel's API); provider method throwing a non-OAuth error repeatedly; network-level failures to the channel endpoint; invoking a tool with malformed arguments that the provider silently fails on.
Related errors
- Failed to fetch URL
- File is too large.
- Unsupported file type.
- All media must be uploaded through our upload API route and
- Post validation failed
AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27).
Data as JSON: /api/errors/42219c060b30109c.
Report an issue: GitHub.