A Post Failed to Publish: What the Error Means and How to Fix It
A plain-language catalogue of publish failures — authorisation, content rules, media, rate limits and platform outages — with the exact fix for each and a safe retry procedure.
FIX IT
A failed publish is the moment a scheduling tool stops being a convenience and starts being a liability, so it is worth understanding exactly what happened before deciding what to do about it. The good news is that failures in PostHub are specific: the platform's own refusal text is preserved and shown to you, rather than being swallowed and replaced with something generic.
The bad news is that a refusal text is written by a platform engineer for another platform engineer. This guide translates.
How a failure presents itself
There are three outcomes from any publish action, and they look different in the interface.
Everything succeeded. The post is marked published, each platform has its own post id stored against it, and you are done.
Some platforms succeeded and some refused. This is a partial result, and it is reported as published — because the post did go out. The platforms that refused have their reasons recorded, and you will see a warning telling you how many rejected it. The queue's failed filter does not surface these; open the post and read the per-platform result instead.
Nothing succeeded. The post is marked failed, the request reports an error, and the first reason is shown in the toast. The post still exists — nothing is deleted — and it sits in the queue under the failed filter until you act.
The distinction matters because the fixes are different. A total failure is nearly always about the connection: the account, the token, the permissions. A partial failure is nearly always about the content: one platform's limit, format or policy that the others do not share.
The shape of the message
PostHub does not rewrite platform errors. If Instagram says a token expired, you see that. If Dribbble says the image dimensions are wrong, you see that. The practical benefit is that the message is searchable — paste it into a search engine and you will find the platform's own documentation for it. The cost is that the message sometimes contains internal field names and status codes that look alarming and are not.
Two parts of a message are more useful than they look. A numeric status like 401 or 403 tells you it is an authorisation problem rather than a content problem; 429 tells you it is a rate limit; 400 usually means the request itself was malformed, which in practice means a content rule. And a phrase containing the word permission, scope or grant tells you the account is fine but the app has not been allowed to do the thing you asked.
The catalogue
Authorisation and connection failures
"Reconnect your account" / token expired / session invalid. The stored token has aged out or been revoked. This is the single most common failure and the fastest fix: open Connected Accounts, disconnect that platform, connect it again. The new grant replaces the old one and the post can be published immediately.
"Insufficient permissions" / scope not granted. The account connected successfully, but the app was not authorised for the specific action. It happens when a platform product was added after the connection was made, or when the scope list was edited. Fix it on the platform's side, then disconnect and reconnect so the new scopes are captured in the new token. Reconnecting is what re-reads the permissions; editing the app alone changes nothing for a token that already exists.
"Your account is no longer connected." The row that the post was targeting has been removed — someone disconnected the account after the post was scheduled. Reconnect the account, then republish. The post remembers which platform it was for, not which row, so a fresh connection satisfies it.
"No pages available" / no account found on that platform. The integration is connected but cannot find a destination: no Facebook Page is linked to the Instagram or Facebook account, or the account has no business locations for a Google Business Profile post. Create or link the destination on the platform, then reconnect so the app can discover it.
"Not configured on this server." The deployment does not have the environment keys for that platform. This is an administrator problem rather than a content problem: add the variables, restart, verify with the health endpoint, then reconnect.
A 401 with no other explanation. Treat it as expired or wrong credentials. Reconnect first; if the failure repeats immediately after a fresh connection, the client secret on the server is wrong, and the fix belongs in the environment panel.
A 403 with no other explanation. Treat it as approval or permission rather than credentials. The app is authenticated but not allowed — app review pending, product not approved, test-user list not containing this account, or a private/protected account where public posting is required.
Content rule failures
"Post is too long" / text exceeds the limit. The caption is over the destination's character limit. Open the post, shorten it for that platform using the per-platform override, and republish. Note that X counts links as a fixed short length regardless of the real URL, so a caption that looks long in the composer may still fit — and conversely, a caption that fits everywhere except one platform needs only that one platform's version shortened.
"Post is empty." The text field is blank for that platform, which usually means a per-platform override was filled with whitespace or the global text was cleared after the override was written. Put the text back and republish.
"Media required." The platform will not accept a text-only post — Instagram, Threads, LinkedIn, Dribbble, Pinterest, YouTube, TikTok and Vimeo all behave this way. Attach an image and republish.
"Image too large" / "unsupported media type" / dimension errors. All three are media problems and all three are covered in detail in the media requirements guide. The short version: compress, change format to JPG or PNG, or resize to the exact dimensions the platform demands.
"Title required." A platform that expects a title field — YouTube-style destinations — was given a post without one. This is a content-structure failure rather than a length or media problem.
Rate limits and quotas
"Rate limit exceeded" / 429. You published too often to that platform in too short a window, or the platform is applying a global limit. Nothing is broken. Wait, then retry — the platforms that already succeeded are skipped on the retry, so the only thing that goes out again is the post that was refused.
Daily cap reached. Threads, TikTok, YouTube and X all have daily budgets that reset on their own schedule, not yours. The failure is accurate and the fix is patience. If you hit a daily cap regularly, the volume is ahead of what that platform allows and the schedule needs to change rather than the tool.
Quota consumed by something else. YouTube's quota is shared across uploads and other API calls, so a day of heavy activity can exhaust it before your scheduled upload lands. The error names the quota rather than your post.
Platform-side problems
"Service unavailable" / 5xx / timeout. The platform is having a moment. Retry once. If it fails twice in a row, it is not your content and not your account — come back later, because the post is still safely in the queue and nothing has been lost.
"Network error" / could not reach the platform. The server could not open a connection at all. On a self-hosted deployment this is a firewall or DNS problem rather than a platform outage; on a hosted deployment it is almost always the platform.
"Unexpected response" / bad response. The platform answered with something the adapter does not recognise. This usually means the platform changed something, or that an intermediary (a proxy, a WAF) altered the response. Capture the message and report it — this is the category where a genuine bug is most likely.
"Not implemented yet." The platform is listed but this particular action is not supported for it. It is an honest refusal rather than a failure: nothing was sent, nothing is broken.
A triage procedure that takes a minute
When a post fails, resist the urge to change five things at once. Work down this list, one question at a time.
Is it one platform or all of them? All of them means connection or content. One of them means that platform's specific rule.
Is the account still connected? Open Connected Accounts and look at the badge. Anything other than Connected — and in particular a token that is technically present but revoked — is your answer, and reconnecting is your fix.
Is the message about permissions or about content? Permission, scope, grant, authorised, forbidden: fix on the platform side, then reconnect. Length, empty, media, dimension, format: fix the post, then republish.
Did it start after a change? A change to the app's scopes, a password reset on the platform, a new environment variable, a migration: those are the four events that reliably break previously working connections. Reverse the change or complete it.
Has it failed more than once with the same message? If yes, you are not going to fix it by retrying. Change something between attempts — that is the whole discipline of retries.
Is the post still in the queue as failed? It is. Nothing is lost, nothing is auto-deleted, and the content is intact. Fix the cause and publish again from the calendar.
Retrying safely, and what retrying does not do
Pressing publish again on a failed or partially failed post re-runs the engine across every targeted platform, and skips the ones that already have a platform post id. So a retry after a partial failure touches only the platforms that refused, and a retry after a total failure touches all of them.
That skip is what makes retries boring, which is what you want. There is no scenario where fixing one platform's problem causes a duplicate on another.
What retrying does not do is diagnose. The second attempt will fail with the same message if you have not changed the cause, and it will fail fast, because the platform is consistent about its rules. If you find yourself pressing publish a third time without having changed anything, stop — the answer is in the message, not in the attempt count.
The one exception is an outage. Platform-side 5xx errors are worth one immediate retry and one retry a few minutes later, because the outage may clear while you are reading the message.
Reconnect, edit, or wait: choosing the right one
The three possible responses map cleanly onto the three categories.
Reconnect when the message is about authorisation — expired, invalid, forbidden, permission, scope. Do it from Connected Accounts, and do it on the platform that failed, not on a different one that happens to be convenient.
Edit the post when the message is about content — length, empty, media, dimensions, title. Change the post rather than the account, and prefer the per-platform override so that one platform's constraint does not shorten the version everyone else receives.
Wait when the message is about the platform — rate limits, quotas, outages. The post is still scheduled or failed in your queue, the content is safe, and retrying early only spends another attempt.
A fourth response, occasionally correct, is accept it. Some posts are not worth reworking: a text-only idea on a platform that demands media, a link post on X where the URL makes the API cost twenty times higher than a plain one, a video idea in a composer that only takes images. Removing that platform from the selection is a legitimate outcome, and doing it deliberately is better than discovering the failure every time you publish.
Prevention is cheaper than triage
Six habits eliminate most of the failures this guide describes.
Keep one platform out of every cross-post until you have proven that platform accepts the format. Prove it once with a real post, then include it everywhere.
Reconnect any account that has gone more than about two months without publishing, because that is roughly when short-lived tokens and revocations start to bite.
Watch the media checklist before publishing: JPG or PNG, under 10 MB, under 976 KB for Bluesky, exact dimensions for Dribbble.
Keep a per-platform override on every post that is going somewhere with a much tighter limit than the others, rather than hoping the global text fits.
Read the first failure rather than the headline status. A published post with one rejected platform is a partial result, and the rejected platform will still be there tomorrow.
Re-check config after any environment change, so that a missing key shows up as a badge on the accounts page rather than as an error during your next publish.
What to include when you report it
If you have worked through the list and the failure is still unexplained, the information that gets you an answer fastest is small and specific:
The full error text from the toast, unedited. It names the platform's own reason.
The platform, and whether it was a total failure or one of several.
Whether the account shows Connected on the accounts page at the time of the failure.
Whether anything changed recently — a scope edit, a password change, a deploy, a migration.
That is enough to distinguish a content rule from a token problem from a platform outage without a single round trip of follow-up questions. Screenshots of all four are better still, because the badge and the timestamp carry information that a paraphrase drops.
What is not a failure at all
A certain amount of panic in a scheduling tool is caused by things that are working correctly, so it is worth naming them.
The post has not gone out yet. The scheduler wakes once a minute and drains what is due. A post scheduled for 10:00:00 can legitimately still show scheduled at 10:00:40. If it is still scheduled several minutes later, then check further — but the first sixty seconds are not a failure.
The status says published and you see a warning. That is a partial result, not a broken one. Something went out. The warning names the platform that refused, and the fix is on that platform only.
The queue and the calendar disagree. They read the same rows. If they appear to disagree, one of them is filtered or showing a different day — check the filters before assuming data corruption.
A platform is greyed out or missing. Either its keys are not configured, or its feature flag is off, or you have not published there yet so it is not in the list of destinations. None of those is a publish error; they are conditions that prevent you from reaching the point where an error could occur.
A platform refuses an action that PostHub says is not supported. That is an honest boundary rather than a bug: nothing was sent, no quota was spent, and the post did not move.
The test for all five is the same: did the system send something and get refused? If nothing was sent, you are looking at a precondition, and preconditions are fixed in settings rather than in the post.
Per-platform refusals you will see most often
Every platform has one or two rules that catch people repeatedly. These are the ones that generate the most tickets.
X. Two limits dominate. The length limit is 280 characters, and X counts a URL as a fixed short length rather than its real length — so a caption with a link is shorter than it looks. And API costs: a post containing a URL costs twenty times what a plain post costs against X's API budget, which surfaces as a rate-limit style failure on a busy day. Fix: plain posts for high volume, link posts where they earn their cost.
Instagram. Media is not optional, the caption limit is 2200 characters, and the destination must be a business account linked to a Facebook Page. The refusal that surprises people is the last one: the connection works, the image is fine, and the account simply is not the right kind of destination.
Facebook. Pages, not personal profiles, are the publishing destination. If your connection returns no pages, the cause is upstream — a Page that does not exist or is not owned by the account you connected.
Threads. Media required, 500 characters, and a hard daily posting budget that resets on the platform's schedule.
LinkedIn. 3000 characters, media required, and the token needs the member-level sharing scope. A post that used to work and now fails with a scope message usually means the app's permissions were edited after the connection was made — reconnect after fixing them.
YouTube. Video only, a title is required, and quota is shared across every API call the project makes. Running other tools on the same Google project can consume the quota your upload needed.
TikTok. Video only, and the account must be a business or creator account with the right app permissions. A rejected upload that returns an account-type message is fixed in TikTok's settings, not in the post.
Dribbble. The strictest media rule in the product: exactly 400x300 or 800x600, JPG, PNG or GIF, and a maximum of 1000 characters. Anything else is refused before the image is even considered, and the upload itself also needs Dribbble to approve the application for upload access.
Pinterest. Needs a business account, an image, and a destination board. A refusal naming a board means the board lookup failed, not that the pin was rejected.
Telegram. The bot must be a member of the target chat and someone must have spoken in it. If it is in a channel, the bot needs posting rights there.
Bluesky. No video at all, images capped under about 0.95 MB, and four images maximum. This is the platform that fails most often on media size despite the file being small by everyone else's standards.
Knowing your platforms' top two rules removes roughly half of all failures before they happen — which is the actual point of the media guide and the platform limits reference.
Four worked scenarios
Abstract rules are hard to apply at 9 pm. Here is the triage list running against four real situations.
Scenario one: three platforms, two published, one refused. The post reads published with a warning. Open the post. Two platforms have post ids, one has a message saying the image exceeded the maximum size. Nothing about the account is wrong. Compress the image, open the post, press publish — only the refused platform runs again, because the other two already have their ids. Total time: three minutes. The mistake to avoid here is disconnecting the account: the message was about media, and reconnecting wastes time without touching the cause.
Scenario two: everything failed with a token message. All four platforms refuse, each with its own expired-token text. The account badges on the accounts page still look connected, because a revoked token often still exists. Reconnect one platform, confirm that platform alone publishes, then reconnect the others. If one platform succeeds after reconnect and another still fails with the same message, the difference is between the two accounts — a password change or a revocation on the second one — not between the two attempts.
Scenario three: worked yesterday, fails today with a scope error. Something changed on the platform side: the app's permissions were edited, a product was added, or the account's own role changed. Fix it in the developer portal, then disconnect and reconnect in PostHub — reconnecting is what reads the new scopes into a new token. Retrying without reconnecting will fail identically, because the old token carries the old permissions.
Scenario four: refuses only the post with a link. The message is a rate limit. X's API charges far more per request for a post containing a URL, so the same volume that works with plain posts exceeds the budget with links. The fix is a content decision — fewer link posts on that platform, or spreading them across the day — not a tool problem. This scenario is the one where the correct answer is usually to change the plan rather than the post.
Each scenario resolves by identifying which of the three categories applies before touching anything. That ordering is the entire discipline.
Keeping a failure log
It sounds excessive for a tool you use a few times a week. It pays for itself the first time a failure repeats across a month.
Four fields per entry: the date, the platform, the message, and what fixed it. A note application or a spreadsheet is fine. What you are building is a local knowledge base for your own account's quirks — the platform that always rejects your Tuesday exports, the account that needs reconnecting every six weeks, the image size that trips you up.
Three patterns become visible within a month that are invisible in the moment. A failure that recurs on the same day each week points at a scheduling or quota problem rather than content. A failure that always follows a particular workflow points at how that workflow exports its media. And a message you have already solved stops costing you twenty minutes the second time, because you recognise it rather than re-deriving it.
If the log only ever contains six lines, it will still have saved more time than it took.
Recovering from a platform-wide incident
Occasionally the failure is not yours at all — the platform is down, its API is degraded, or an intermediary between you and it is having a bad hour. The recovery procedure has a shape.
Do not bulk-retry during the incident. Every attempt spends time and, on some platforms, budget. The post is safe in the queue.
Check whether the incident is over by publishing one small test post to the affected platform rather than by retrying the whole backlog. One success tells you the path is clear.
Republish in the order the posts were meant to go out, oldest first, checking after each one that it landed. The skip logic means platforms that already succeeded are untouched, so the only risk in this phase is publishing a stale post you no longer want — read the list before you press anything.
Remove anything that has expired. A post that was meant to announce something on Wednesday is not worth publishing on Friday. Deleting a scheduled post is always available and is frequently the right call after an outage.
Write one line in your failure log about the incident. Future-you seeing a repeated message needs to know that the last three times were a platform problem rather than a content problem.
When a failure is genuinely a bug
Most messages are the platform being honest. A smaller number indicate something on this side, and it is worth knowing how to tell the difference.
Suspect a bug when the same message appears on a platform whose rules the content clearly satisfies — a two-word post refused for being too long, an image refused for a dimension it does not have, a connection that the accounts page reports as healthy failing immediately. Those are contradictions, and contradictions do not come from platform validation.
Suspect the platform when the message contains internal field names, unusual status codes, or wording that does not match any documented rule.
Report it with the four items listed in the previous section: the full message, the platform, the connection status at the time, and what changed recently. Add the post's id if you have it. A contradictory message with those four attached is usually reproducible from the report alone, which is the difference between a one-day fix and a week of questions.
After it publishes: edits, takedowns and second thoughts
Publishing is not the end of the story, and three situations after a successful publish cause the same panic as a failure while needing a completely different response.
You need to change a published post. Most platforms allow editing of their own posts through their own interfaces, and the platform post id recorded against your PostHub post is the shortcut to it — the post detail carries the link to what was actually created. Editing in PostHub does not push the change to a post that already exists on the network; the two are separate from the moment of publishing. If the edit matters on the platform, make it there.
You need to remove a published post. Removal is a platform-side action: open the post on that network and delete it. Doing it in PostHub removes your record of it, not the post itself, which is a distinction worth understanding before you rely on it for a takedown.
The platform removed it for you. This is the one that feels like a failure but is entirely downstream: the publish succeeded, the id was recorded, and afterwards the platform's moderation, a copyright claim, or an account-level restriction took it down. The message you receive will come from the platform's notification channels rather than from a PostHub error, because from the publishing system's point of view nothing went wrong.
That third case has one useful diagnostic: a post removed after successful publication tells you about the content or the account standing, not about your configuration. Re-publishing the same material will usually meet the same fate, so the fix belongs in what was posted rather than in how it was sent.
Related and worth separating: a post that appears in the platform's own interface but not to your followers is a visibility setting rather than a failure — a private account, a restricted audience, a scheduled visibility on the destination side. Check the post on the platform before concluding anything from its absence in a feed.
The two-minute post-mortem
After the fix, before you move on, spend two minutes writing one sentence. It is the highest-return habit in this entire guide.
The sentence has three parts: what failed, why, and what you changed. Not a paragraph — a sentence. "Instagram refused the post because the account was switched back to personal, and I relinked it to the Page." That is the whole record.
The value shows up in three places, all later than you would like. The second time the same message appears you recognise it rather than re-deriving the diagnosis, which turns a twenty-minute investigation into a thirty-second one. When a pattern emerges — one platform failing every week, failures clustering on a particular day — the sentences line up into a cause that no single incident reveals. And when someone else asks what happened last Tuesday, the sentence answers it without anybody reconstructing the week from memory.
Where to put it: a note file, the same one you used for week-one setup, is fine. A dedicated log is better if failures are frequent. What matters is that it is dated and searchable, not that it is in the right tool.
If you skip this step, the failure is not really fixed — it is only resolved, and resolution without a record has a habit of recurring in a form you do not quite recognise.
The short version
Failures are specific, they are preserved, and they are almost always one of three things: the account needs reconnecting, the content needs adjusting, or the platform needs time. Identify which of the three you are looking at before changing anything, fix that one thing, and republish — the platforms that already received the post will be left alone.
Put this playbook on autopilot
PostHub queues, publishes and reports across every platform you use — so the strategy above actually happens without you babysitting a tab.