gitroomhq/postiz-app · error · BadBody

X could not create the article draft

Error message

X could not create the article draft

What it means

When publishing an X (Twitter) article/long-form post, the draft-creation response has no data.id. The provider logs any returned errors and throws BadBody 'X could not create the article draft', meaning the article never entered draft state.

Source

Thrown at libraries/nestjs-libraries/src/integrations/social/x.provider.ts:1115

          : {}),
      }),
    });
    const draftJson = (await draftResponse.json()) as {
      data?: { id: string };
      errors?: any[];
    };

    // The articles endpoints can return 2xx with an errors array (e.g. a
    // rejected cover) - don't swallow it.
    if (draftJson?.errors?.length) {
      console.log(
        'X article draft returned errors:',
        JSON.stringify(draftJson.errors)
      );
    }

    if (!draftJson?.data?.id) {
      throw new BadBody(
        this.identifier,
        JSON.stringify(draftJson),
        Buffer.from('{}'),
        'X could not create the article draft'
      );
    }

    if (settings.article_status !== 'published') {
      return {
        status: 'completed',
        postId: draftJson.data.id,
        releaseURL: `https://x.com/i/articles`,
      };
    }

    const publishUrl = `https://api.x.com/2/articles/${draftJson.data.id}/publish`;
    const publishResponse = await this.fetch(publishUrl, {
      method: 'POST',

View on GitHub (pinned to 0f1647f749)

Solutions

  1. Inspect draftJson (attached to the BadBody) for the errors array details
  2. Verify the connected X account has Articles access enabled
  3. Ensure the OAuth app requests the article/long-form write scopes
  4. Simplify the article payload (plain text first) to isolate validation failures
Defensive patterns

Strategy: validation

Validate before calling

// before publishing, confirm the account can use articles
const me = await client.get('users/me');
if (!(me.data as any)?.is_article_supported) { /* fall back to a regular post */ }

Type guard

const hasArticleDraftId = (j: unknown): j is { data: { id: string } } => Boolean((j as any)?.data?.id);

Try / catch

catch (e) { if (e instanceof BadBody && e.message.includes('article draft')) { /* inspect errors array, fall back to normal post if unsupported */ } throw e; }

Prevention

When it happens

Trigger: X's article draft endpoint returns errors array (auth scope missing, validation error on the article payload) or an unexpected envelope without data.id.

Common situations: App/user token lacks the article (long-form) scope; article payload (title/body/markdown) fails X's validation; X Articles feature not enabled for the account; X API change to the article endpoint shape.

Related errors


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