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

  1. Manually check the X account to see whether the tweet was actually published
  2. Delete the duplicate on X if it went out, then retry or dismiss the pending post
  3. Avoid deploying/restarting workers while posts are mid-flight
  4. 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

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


AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27). Data as JSON: /api/errors/4a19eed0abfe7319. Report an issue: GitHub.