gitroomhq/postiz-app · error · PostValidationException
Post validation failed
Error message
Post validation failed
What it means
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.
Source
Thrown at apps/backend/src/public-api/routes/v1/public.integrations.controller.ts:231
)
) {
throw new HttpException(
{
msg: `All media must be uploaded through our upload API route and contain the domain: ${process.env.RESTRICT_UPLOAD_DOMAINS}`,
},
400
);
}
// Server-side validation — same rules as the dashboard, surfaced as a
// readable 400 (see PostValidationExceptionFilter).
const validation = await this._postsService.validatePosts(
org.id,
body.posts
);
const fail = (item: (typeof validation)[number], error: string) => {
throw new PostValidationException({
provider: item.identifier,
name: item.name,
error,
});
};
for (const item of validation) {
if (item.emptyContent) {
fail(
item,
'Your post should have at least one character or one image.'
);
}
}
if (body.type !== 'draft') {
for (const item of validation) {
if (!item.valid) {View on GitHub (pinned to 0f1647f749)
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
Example fix
// before
{ "posts": [{ "integration": { "id": "disconnected-channel" }, "value": [] }] }
// after
{ "posts": [{ "integration": { "id": "connected-channel" }, "value": [{ "content": "Hello!" }] }] } Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate your payload shape before sending
for (const post of posts) {
if (!post.integration?.id) throw new Error('Missing integration id');
if (!post.value?.length) throw new Error('Post has no content entries');
for (const v of post.value) {
if (!v.content?.trim() && !(v.image?.length || v.video?.length)) {
throw new Error('Entry needs text or media');
}
}
} Type guard
null
Try / catch
try {
await api.createPost({ posts });
} catch (e) {
if (e instanceof PostValidationException || e?.response?.data?.msg === 'Post validation failed') {
const { provider, name, error } = e.response.data; // per-post detail drives the fix
console.error(`Post for ${provider}/${name} failed: ${error}`);
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- File is too large.
- Unsupported file type.
- All media must be uploaded through our upload API route and
- Integration not allowed
- All posts must have an integration id
AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27).
Data as JSON: /api/errors/39bcb42406f8a160.
Report an issue: GitHub.