gitroomhq/postiz-app · error · BadRequestException
Only scheduled posts that were not published yet (or drafts)
Error message
Only scheduled posts that were not published yet (or drafts) can be updated
What it means
Only posts in state QUEUE (scheduled, not yet published) or DRAFT can be updated. Once a post transitions to PUBLISHED (or another terminal state) the update path refuses it, preventing edits to already-delivered content.
Source
Thrown at libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts:998
settings: Record<string, any>,
creationMethod: CreationMethod
): Promise<{ postId: string; publishDate: string }> {
// Ordered as post -> comments, root includes integration and tags.
const ordered = await this.getPostsRecursively(postId, true, orgId, true);
const [root] = ordered;
if (!root) {
throw new NotFoundException('Post not found');
}
if (root.parentPostId) {
throw new BadRequestException(
'This id belongs to a comment, pass the id of the main post'
);
}
if (root.state !== 'QUEUE' && root.state !== 'DRAFT') {
throw new BadRequestException(
'Only scheduled posts that were not published yet (or drafts) can be updated'
);
}
if (
root.state === 'QUEUE' &&
dayjs.utc(root.publishDate).isBefore(dayjs.utc())
) {
throw new BadRequestException(
'The publish time of this post already passed, it cannot be updated'
);
}
const integration = (root as any).integration;
let existingSettings: Record<string, any>;
try {
existingSettings = JSON.parse(root.settings || '{}');View on GitHub (pinned to 0f1647f749)
Solutions
- Refresh the post state; if it is PUBLISHED, create a new post instead of updating
- For queue/draft posts, retry the update after confirming state via getPostById
- If editing published content is truly needed, clone the post and schedule it anew
- Subscribe to post state change events so the UI locks editing when state leaves QUEUE/DRAFT
Example fix
// before
await updatePost(orgId, postId, body);
// after
const post = await getPostById(orgId, postId);
if (post.state === 'QUEUE' || post.state === 'DRAFT') {
await updatePost(orgId, postId, body);
} else {
await createPost(orgId, { ...body, type: 'schedule' }); // new post
} Defensive patterns
Strategy: validation
Validate before calling
const post = await getPostById(orgId, postId); const editable = post?.state === 'QUEUE' || post?.state === 'DRAFT'; if (editable) await updatePost(orgId, postId, body);
Type guard
const isEditableState = (s: string): s is 'QUEUE' | 'DRAFT' => s === 'QUEUE' || s === 'DRAFT';
Prevention
- Lock the editor when the post's state leaves QUEUE/DRAFT
- Refetch state right before save on long-lived editor sessions
When it happens
Trigger: Calling updatePost on a post whose state is PUBLISHED, ERROR, or any state other than QUEUE/DRAFT — e.g. editing a post that has just gone out while the calendar was still open.
Common situations: Race between scheduler publishing the post and the user clicking save; stale calendar state after a websocket refresh; attempting to 'edit history' of published posts via the API.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Integration with id ${post?.integration?.id} not found
- This post was already published on ${dayjs .utc(post.publi
- The publish time of this post already passed, it cannot be u
- Failed to update the post
- Post validation failed
AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27).
Data as JSON: /api/errors/9e5f3b3048f7e6bd.
Report an issue: GitHub.