Brief & Hire
Field notes · August 2026

The API said my posts failed. All five were live, and the retries kept going

Incident log · August 2026

What ran
A scheduled social-media publishing job with a retry ladder, a publish ledger and phone alerts
What I saw
Over two days, five posts were recorded as failed after the platform's API returned a request-limit error or a fatal error. The retries kept going and a failure alert reached my phone.
Why
The error did not mean the post had not gone out. All five were already published. The job trusted the error message instead of checking the account, and the code that did check the account sat on a path the scheduler never used.
What it cost
The retry ladder kept hitting posts that were already live, three of which went out within five minutes while it was still retrying. The ledger used to prevent duplicates was not updated, so the next slot could have published them again. The API has no delete, so a duplicate has to be removed by hand.
What changed
On any publishing error, the job now looks for the post on the account first. If it is there, the run counts as a success and the ledger is written. Only if it is missing is it a failure, and a limit error stops the slot instead of retrying.

What I expected

My publishing job runs on a schedule. In each slot it takes the next prepared post from a queue and publishes it through the social platform’s official interface. Around that step I had three pieces of safety:

  • A retry ladder. If publishing returns an error, wait and try again a few times.
  • A ledger. Every published post is written to a record, and the job refuses to publish anything already in it. That is the duplicate guard.
  • A phone alert. If a slot ends in failure, a message reaches me.

The assumption under all three was simple: if the interface says the publish failed, the post did not go out.

What actually happened

On August 11 and 12, five posts were recorded as failed. The interface had returned either “application request limit reached” or a generic fatal error. When I opened the account, every one of them was there:

Post What the interface returned What was actually on the account
1 limit error, then fatal, then fatal live, Aug 11 19
2 limit error live, Aug 12 09
3 limit error live, Aug 12 09
4 limit error live, Aug 12 09
5 limit error live, Aug 12 13

The damage came in three parts:

  1. The retries kept hitting work that was already done. Three posts went out in five minutes while the ladder was still treating them as failures.
  2. The duplicate guard broke. Because the job believed each publish had failed, it never wrote those posts to the ledger. The next slot would have seen them as unpublished and sent them again.
  3. The alert told me the wrong thing. “Publish failed” arrived on my phone. The alert worked perfectly. It faithfully delivered a wrong verdict.

There is no delete in that interface. Had a retry produced a duplicate, it would have had to be found and removed by hand in the app.

Why

Three things combined.

An error is not a receipt. The publish request can succeed on the platform’s side and still come back with an error, in this case a limit error. The limit that was hit was the app’s request allowance, which is separate from the daily posting limit. A single image carousel takes around 80 calls, and at the time the day’s seven publishing slots were packed into daytime hours, so those calls landed close together.

I read the cause backwards. The prepared item behind each post showed an error status after the attempt. For a while my notes said the failed attempt had broken the item. That was wrong. An item that has been used up by a successful publish shows the same status. I had seen “attempt, then error status” and assumed the first caused a failure, when it meant the opposite. Checking the account would have shown that immediately.

The fix existed, on the wrong path. On August 11 I had already added a “check the account before failing” rule, to one of the job’s two publishing commands. The scheduler used the other one. So only the unattended runs kept reporting false failures.

What I changed

On any publishing error, the job now asks the account before deciding anything:

  • It looks for the post among the most recent posts, matching the caption’s first line and the media type. The type matters because the same topic can go out as two formats with the same first line; without it, a new video post would be mistaken for an older image post and skipped.
  • If the post is there, the run counts as a success, and the ledger and the item’s record are written. Publishing again would only create a duplicate.
  • If the post is missing and the error is a limit error, the slot stops at once. A real limit is not helped by more requests.
  • If the item is dead and the post is missing, that is a real failure, and the queue moves on to the next item.

A limit error now never gets a catch-up run, because more requests only use up more of the same limit; catch-up runs are kept for temporary network problems, where trying again later can actually help. Most of the publishing slots also moved out of daytime hours into the evening and night, so the same number of calls no longer lands in one stretch of the day.

What this has to do with hiring someone

A demo will never show this. In a demo, a publish either works or it obviously does not. The false failure only shows up under load, at the limit, unattended.

If you are paying someone to build anything that posts, sends, books or charges, ask in writing: when the service returns an error, how does the automation know whether the action happened anyway? “It retries three times” is not an answer. It is the behaviour that kept hitting my already-published posts and nearly broke my duplicate guard. A good answer describes a check against the real result before any retry, and says which errors are worth retrying at all.

This is the same idea as an idempotent run, applied to the one moment where it is easiest to get wrong. It belongs next to the duplicate-run test in the acceptance checklist for unattended automations, and if your automation is already sending duplicates, a false failure followed by a retry is one of the first causes to rule out. Then ask the freelancer one more thing: which path does the scheduler actually run, and was the fix tested there?

What I put in a brief now

  • Ask that any step which posts, sends or charges checks whether the action already happened before it retries.
  • Ask which code path the scheduler actually runs, and test the fix on that path.
  • Ask how a duplicate would be undone if the service offers no delete, and who would do it.

If you are hiring for this