gitroomhq/postiz-app · error · BadRequestException

All posts must have an integration id

Error message

All posts must have an integration id

What it means

PostsService.mapTypeToPost requires every entry in body.posts to carry an integration.id before it can map a submitted post to persisted posts. The integration id identifies which connected social channel the post targets; without it the post cannot be routed to a provider.

Source

Thrown at libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts:254

  async getStatistics(orgId: string, id: string) {
    const getPost = await this.getPostsRecursively(id, true, orgId, true);
    const content = getPost.map((p) => p.content);
    const shortLinksTracking = await this._shortLinkService.getStatistics(
      content
    );

    return {
      clicks: shortLinksTracking,
    };
  }

  async mapTypeToPost(
    body: CreatePostDto,
    organization: string,
    replaceDraft: boolean = false
  ): Promise<CreatePostDto> {
    if (!body?.posts?.every((p) => p?.integration?.id)) {
      throw new BadRequestException('All posts must have an integration id');
    }

    const mappedValues = {
      ...body,
      type: replaceDraft ? 'schedule' : body?.type,
      posts: await Promise.all(
        body?.posts?.map(async (post) => {
          const integration = await this._integrationService.getIntegrationById(
            organization,
            post.integration.id
          );

          if (!integration) {
            throw new BadRequestException(
              `Integration with id ${post.integration.id} not found`
            );
          }

View on GitHub (pinned to 0f1647f749)

Solutions

  1. Ensure every item in posts[] includes the id of a connected integration (e.g. posts: [{ integration: { id: '<integrationId>' }, content: '...' }])
  2. Validate the payload client-side before submitting: posts.every(p => p?.integration?.id)
  3. If the integration was deleted, re-connect the channel to get a new integration id and resubmit
  4. Check the CreatePostDto parsing if a custom client strips unknown properties such as integration

Example fix

// before
{ type: 'schedule', posts: [{ content: 'Hello' }] }
// after
{ type: 'schedule', posts: [{ integration: { id: integrationId }, content: 'Hello' }] }
Defensive patterns

Strategy: validation

Validate before calling

const ok = body?.posts?.length > 0 && body.posts.every((p) => p?.integration?.id);
if (!ok) throw new Error('Select a channel for every post variant');

Type guard

const hasIntegrationIds = (b: CreatePostDto): boolean =>
  Array.isArray(b?.posts) && b.posts.length > 0 && b.posts.every((p) => !!p?.integration?.id);

Prevention

When it happens

Trigger: POST /organization/:orgId/posts (createPost) or a draft replace where body.posts contains an item with a missing or null integration, or the posts array itself is undefined (every() on undefined short-circuits the guard via optional chaining and fails).

Common situations: Client sends { posts: [{ content: 'hi' }] } without selecting a channel; integration object dropped by a form state bug; API consumers building payloads manually and omitting integration; draft payloads where integration was not persisted.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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