{"record":{"id":"39bcb42406f8a160","repo":"gitroomhq/postiz-app","slug":"post-validation-failed","errorCode":null,"errorMessage":"Post validation failed","messagePattern":"Post validation failed","errorType":"validation","errorClass":"PostValidationException","httpStatus":400,"severity":"error","filePath":"apps/backend/src/public-api/routes/v1/public.integrations.controller.ts","lineNumber":231,"sourceCode":"      )\n    ) {\n      throw new HttpException(\n        {\n          msg: `All media must be uploaded through our upload API route and contain the domain: ${process.env.RESTRICT_UPLOAD_DOMAINS}`,\n        },\n        400\n      );\n    }\n\n    // Server-side validation — same rules as the dashboard, surfaced as a\n    // readable 400 (see PostValidationExceptionFilter).\n    const validation = await this._postsService.validatePosts(\n      org.id,\n      body.posts\n    );\n\n    const fail = (item: (typeof validation)[number], error: string) => {\n      throw new PostValidationException({\n        provider: item.identifier,\n        name: item.name,\n        error,\n      });\n    };\n\n    for (const item of validation) {\n      if (item.emptyContent) {\n        fail(\n          item,\n          'Your post should have at least one character or one image.'\n        );\n      }\n    }\n\n    if (body.type !== 'draft') {\n      for (const item of validation) {\n        if (!item.valid) {","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/gitroomhq/postiz-app/blob/0f1647f7491a217d43eb5ae7a480484bdf0aff3e/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts#L213-L249","documentation":"createPost runs posts through _postsService.validatePosts; the local fail() helper throws PostValidationException with 'Post validation failed' carrying per-post details (provider identifier, name, and the specific error). This is the generic envelope for any rule the post violates — the actionable detail is in the exception payload, not the message.","triggerScenarios":"POST /public/v1/posts where one of the posts fails service-level validation: missing/invalid integration reference, empty content for a provider requiring text, invalid scheduling, unsupported media for the target provider, deleted/disconnected channel, etc. Any per-post rule inside validatePosts trips it.","commonSituations":"Referencing an integration that was disconnected; sending image-only posts to a text-only provider; malformed date/ISO strings; posts whose media list doesn't satisfy the provider's requirements.","solutions":["Inspect the exception response body — provider/name/error fields identify exactly which post and which rule failed","Verify each post's identifier matches a currently connected integration for the organization","Ensure content/media satisfy the target provider's requirements (text length, media count/type)","Correct date formats and retry, fixing posts one at a time if the payload is large"],"exampleFix":"// before\n{ \"posts\": [{ \"integration\": { \"id\": \"disconnected-channel\" }, \"value\": [] }] }\n\n// after\n{ \"posts\": [{ \"integration\": { \"id\": \"connected-channel\" }, \"value\": [{ \"content\": \"Hello!\" }] }] }","handlingStrategy":"try-catch","validationCode":"// Pre-validate your payload shape before sending\nfor (const post of posts) {\n  if (!post.integration?.id) throw new Error('Missing integration id');\n  if (!post.value?.length) throw new Error('Post has no content entries');\n  for (const v of post.value) {\n    if (!v.content?.trim() && !(v.image?.length || v.video?.length)) {\n      throw new Error('Entry needs text or media');\n    }\n  }\n}","typeGuard":"null","tryCatchPattern":"try {\n  await api.createPost({ posts });\n} catch (e) {\n  if (e instanceof PostValidationException || e?.response?.data?.msg === 'Post validation failed') {\n    const { provider, name, error } = e.response.data; // per-post detail drives the fix\n    console.error(`Post for ${provider}/${name} failed: ${error}`);\n  }\n}","preventionTips":["Read the provider/name/error fields in the response — they pinpoint the failing post","Keep integration ids in sync with connected channels (re-fetch before posting)","Satisfy per-provider content and media requirements client-side first"],"tags":["validation","posts","public-api"],"backgroundTag":"schema-validation-failed","analyzedSha":"0f1647f7491a217d43eb5ae7a480484bdf0aff3e","analyzedAt":"2026-08-27T12:09:55.020Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}