gitroomhq/postiz-app · error · BadBody
Tumblr did not return a valid post response
Error message
Tumblr did not return a valid post response
What it means
createMultipartPost expected an object response with a .response field from Tumblr's multipart post API, but axios returned a non-object (usually a string). This happens when a proxy/WAF/HTML page answers with 200 but non-JSON, which would otherwise publish with an empty post id.
Source
Thrown at libraries/nestjs-libraries/src/integrations/social/tumblr.provider.ts:550
});
}
const { data: response } = await this.getSsrfSafeAxios().post(
`${TUMBLR_API_URL}/blog/${encodeURIComponent(blogName)}/posts`,
formData,
{
headers: {
...formData.getHeaders(),
Authorization: `Bearer ${accessToken}`,
'User-Agent': TUMBLR_USER_AGENT,
},
}
);
// axios parses JSON silently: a non-JSON 200 (proxy/WAF page) comes
// back as a raw string, which would publish the post with an empty id.
if (!response || typeof response !== 'object' || !response.response) {
throw new BadBody(
this.identifier,
String(response || '{}'),
'{}',
'Tumblr did not return a valid post response'
);
}
return response as TumblrCreatePostResponse;
}, this.identifier);
}
private async createContentBlocks(post: PostDetails<TumblrDto>) {
const content: TumblrContentBlock[] = [];
if (post.settings?.title) {
content.push({
type: 'text',
subtype: 'heading1',View on GitHub (pinned to 0f1647f749)
Solutions
- Log the raw response string attached to the BadBody to see what actually came back
- Retry after a short wait — WAF/rate-limit pages are often transient
- Bypass proxies/VPNs for api.tumblr.com, or add it to proxy allowlists
- If the envelope genuinely changed (no .response field), update the parser to the current Tumblr API shape
Defensive patterns
Strategy: retry
Validate before calling
if (typeof parsed === 'string' || parsed?.startsWith('<')) { /* non-JSON response: back off and retry later */ } Type guard
const isTumblrPostResponse = (r: unknown): r is { response: { id: string } } => typeof r === 'object' && r !== null && 'response' in (r as object); Try / catch
catch (e) { if (e instanceof BadBody && e.message.includes('valid post response')) { /* retry with backoff; likely WAF/proxy page */ } throw e; } Prevention
- Retry on non-JSON 200s — they are usually transient proxy/WAF pages
- Keep api.tumblr.com out of transform proxies that mangle bodies
- Alert when a non-JSON body is received so silent envelope changes are caught
When it happens
Trigger: A 200 response whose body is HTML (Cloudflare interstitial, captive portal, rate-limit page) so axios returns a raw string instead of parsed JSON; or the API shape changed so response.response is missing.
Common situations: Self-hosted Postiz behind a corporate proxy; Tumblr API returning an unexpected envelope after an API version change; network middleboxes tampering with responses.
Related errors
AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27).
Data as JSON: /api/errors/c50a68746a5ecccc.
Report an issue: GitHub.