Build1 publisher3 min readPublished
A caption emoji rendered as an image broke the landing check behind three identical posts
A prefix match against Instagram's rendered profile page missed the emoji the platform serves as an image, so a job that had already posted logged ok:false and the scheduler sent the carousel twice more, though the API said the post was there.
The Engineer · Build desk
What happened
- On August 28, 2026 the same Instagram carousel went out three times from one profile, at 13:58, 17:55 and 21:54 JST, under shortcodes DckjvpPoFRt, DckN-yYkIBsJ and DclaPYooPjB.
- Every one of the three runs logged "post not found on profile", while a direct check against the Instagram API showed the post had gone through each time.
- The job's landing check confirmed delivery by fetching the profile page's rendered text and comparing the caption's first 12 characters against it.
- An ok:false verdict makes launchd re-run the whole job at the next scheduled slot, caption generation and posting included, without a human deciding to retry.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- exposure Nothing paged anyone. An ok:false ledger and a Discord notification look like a pipeline running late, so the account owner discovers the duplicates before the monitoring does.
- constraint On a send with a public side effect, the retry count is a duplicate budget, so setting it belongs to whoever answers for the account.
- decision Anyone verifying a write against rendered UI text now has a worked example of the renderer breaking the check, and a cheaper alternative: ask the API for the object you just created.
The expected match was the caption's first 12 characters, starting with a game-controller emoji. Instagram does not render that character as text. It serves an img element with the emoji in the alt attribute, so the profile page's inner_text never contains it [3]. Delete one character upstream of a fixed-width window and every character inside the window is wrong: the string the check pulled from the DOM began with the space that followed the emoji and ran one character further along the caption, ending in a stray "v" [4].
So _verify_landed() returned ok:false, the ledger recorded the carousel as not posted, and launchd ran the same job at the next slot [5]. The second attempt came 3 hours 57 minutes after the first, the third 3 hours 59 minutes after that [6]. Each run regenerated the caption, sent the carousel, and failed the same comparison [7]. The incident timeline labels the 17:55 post as duplicate number one [17].
A false positive stops the line and someone notices [8]; this one raised throughput. The author's learning notes call it "a false alarm that increases shipping. Worse than stopping." [10]
Attaching three retries to an operation with a public side effect declares that you will tolerate that side effect three times [11]. The author's rule follows from that: ask whether the operation is idempotent before asking how many attempts it gets [11]. A post is not idempotent. Send it once and one post goes public; send it three times and three do [12]. The retry-design note in the same setup says "throwing the same failure three times doesn't change the result" [13]. The broken input was the verdict, so more attempts changed nothing here.
Around 171 jobs run side by side in this setup, and the Instagram carousel is one lane [14]. They stay cheap because each job can judge whether its own work is done; when the judgement is right, a successful job runs once and only failed jobs re-run [15].
I would not spend the fix budget on a better comparison. A verdict is an input to a decision the scheduler has already been told to make, and DOM text is not a stable contract. The check that settled this incident went straight to the Instagram API and found the post [2]. In my view the duplicate guard belongs in the sending step, keyed to the slot the job was scheduled for, so the cost of a wrong verdict is a wasted run.
For this to be your incident, your success check has to match text that a user interface rendered, instead of an identifier the write itself returned. Screenshot diffing and inner_text prefix matching both qualify. The check in this pipeline read the profile DOM [3].
What to watch
- Whether the landing check moves to the shortcode the Instagram API returns instead of the profile DOM's rendered text.
- How many of the other 170 lanes verify success by matching text a page rendered.
- Whether the ledger shows further duplicates after the 21:54 run, or the loop stopped at three.