gitroomhq/postiz-app · error · BadBody
X may have already published this post, please check your ac
Error message
X may have already published this post, please check your account before posting again to avoid duplicates
What it means
checkPostStatus detects that a tweet-creation attempt was started (attempting) and the OAuth step was confirmed (confirmed) but the result was never recorded — the activity died mid-flight. X has no cheap idempotency check for tweet creation, so re-running could duplicate the post; it stops with an explicit BadBody warning instead.
Source
Thrown at libraries/nestjs-libraries/src/integrations/social/x.provider.ts:832
},
mediaIds: (media[firstPost.id] || []).filter((f) => f),
...(coverMediaId ? { coverMediaId } : {}),
processingIds,
} as XPendingData,
},
];
}
override async checkPostStatus(
accessToken: string,
pendingData: XPendingData,
integration: Integration
): Promise<PendingCheckResponse> {
// A confirmed create attempt died without reporting its result: X gives
// no cheap way to ask whether that tweet was created, so never run the
// create again - stop with an explicit warning instead.
if (pendingData.attempting && pendingData.confirmed) {
throw new BadBody(
this.identifier,
'{}',
Buffer.from('{}'),
'X may have already published this post, please check your account before posting again to avoid duplicates'
);
}
const client = await this.getClient(accessToken);
// Check every media still transcoding; keep the ones not succeeded yet.
const stillProcessing: string[] = [];
for (const mediaId of pendingData.processingIds || []) {
let processing:
| { state: string; check_after_secs?: number; error?: { message?: string } }
| undefined;
try {
processing = await this.mediaProcessingStatus(client, mediaId);
} catch (err: any) {View on GitHub (pinned to 0f1647f749)
Solutions
- Manually check the X account to see whether the tweet was actually published
- Delete the duplicate on X if it went out, then retry or dismiss the pending post
- Avoid deploying/restarting workers while posts are mid-flight
- If X is timing out frequently, reduce media size to speed up the create call
Defensive patterns
Strategy: fallback
Validate before calling
// before re-running a pending post create:
if (pendingData.attempting && pendingData.confirmed) { /* skip auto-retry; require manual confirmation */ } Type guard
const isUncertainOutcome = (p: { attempting?: boolean; confirmed?: boolean }) => Boolean(p.attempting && p.confirmed); Try / catch
catch (e) { if (e instanceof BadBody && e.message.includes('already published')) { /* check the X account manually; delete duplicate or confirm posted */ } throw e; } Prevention
- Never auto-retry creates after a confirmed-in-flight attempt
- Keep posting activities short so they finish before timeouts
- Monitor pendingData flags in your own integrations to avoid duplicate writes
When it happens
Trigger: Temporal worker crash/timeout between the confirmed create call to X and persisting the result: pendingData.attempting && pendingData.confirmed are both true when the check activity resumes.
Common situations: Activity timeouts on slow X API responses; worker restarts or deploys during posting; network drop after X accepted the create request.
Related errors
- X failed to process the uploaded video${(processing as any)?
- X failed to process the uploaded video${processing?.error?.m
- handleError.value
- X could not create the article draft
- X created the article draft but could not publish it, check
AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27).
Data as JSON: /api/errors/4a19eed0abfe7319.
Report an issue: GitHub.