Skip to content
← Writing

37 of My First 46 Agent Runs Failed. One Bug Caused 36.

6 min read
AI Architecture · Agents · Production Engineering

Most writing about AI agents describes a system the author hopes to build. This one describes a system that has been running the back office of my consulting practice since 3 July, and it opens with the failure count because that is the number I’d want if I were reading someone else’s version of this.

The ledger currently holds 46 runs. 37 ended in error. Seven finished clean. One is marked blocked and one failed, both of which turned out to be the system working.

I can tell you that only because every run writes a row. Most systems I’m asked to review can’t produce this table at all: the failures happened, nobody logged them, and the team’s sense of reliability is a feeling rather than a number. The instrumentation came first here, which is why the rest of this article can be specific.

Before the numbers, the honest scale: 4 documents, 1 lead, one user. This is a small system that does real work for one person, not a platform. Everything below is true at that size and nothing below has been tested at any other.

What it does

The unglamorous half of running a practice alone. A CRM holding leads, projects and milestones. A document engine for quotes and proposals, sharing them through tokenized links so I know when something was opened rather than merely sent. First-party attribution that stamps every conversion with its full touch path at write time, so I can answer where a lead actually came from. A crew of agents on top of all of it: one reads demand signals, one drafts, one grades the drafts against a written rubric and argues with the drafter, one triages inbound mail, one publishes, one edits my strategy document from real outcomes.

And an approval queue. Nothing reaches another human being until I approve it.

The agents never hold database credentials. They reach business data through one gateway that exposes typed tools, which is the reason I’m willing to let them run at all. When an agent gets confused, the damage is bounded by the tools I chose to expose.

The failures, itemized

Straight from the ledger. If you’re skimming, this table is the article:

CountWhat happened
18bridge 500: Request timed out after 300000ms
10Stale, still running after 6 hours, closed by a watchdog
8Closed by the watchdog during the same 300-second-timeout era
1426 NONEXISTENT_VERSION, a platform API version I had pinned had been retired

Look at what is missing from that table. No hallucinated facts. No bad decisions carried out. No message sent to the wrong person. No record corrupted. Every single failure is infrastructure, and the fix for thirty-six of them was a timeout value.

Thirty-six of the thirty-seven are one timeout and its cleanup. A crew cycle needs ten to thirty minutes to think; the harness in front of it gave up at five. The agents died mid-task, their rows sat marked running until a watchdog swept them, and the same bug wrote itself into the ledger under three different names.

The thirty-seventh is the one I’d flag to another builder: a vendor retired the API version string I had hard-coded. One failed publish, a one-line fix, and a lasting argument for treating third-party version pins as configuration rather than constants.

The two failures I’m glad about

The blocked and failed runs both belong to the executor that posts engagement comments. It needs a logged-in browser session, and on two separate runs that session wasn’t there.

Neither run crashed, and neither improvised. Both diagnosed the specific cause, left every approved item untouched for the next run, and wrote what they found into the ledger. One of them recorded that it had considered writing a lower-level script to post directly and rejected the idea as riskier than posting nothing.

That is what failure should look like in a system acting on your behalf. Those two runs cost me a few hours of delay. The same two runs deciding to be helpful could have cost the account.

Three decisions did the work

Approval is the only gate. Everything the crew produces lands in a queue as a draft and waits. After I approve, execution belongs to the machine: the sanctioned platform API where one exists, an agent driving a browser where the platform offers none. Because the gate sits before execution instead of after it, a bad draft costs a click and a broken executor costs a delay.

Everything writes a row. Every run, every publication, every failure with its summary. That ledger is why this article has numbers in it. It is also how a later run diagnosed an earlier one: the system can query its own history of mistakes.

Nothing publishes on assumption. The publisher refuses to post an item that declares an image but carries no image. It refuses outside its window, past its daily cap, and with an expired token. Each refusal appears in the ledger as a run that did nothing, and each one is a post that didn’t go out half-assembled.

What it can’t do

It can’t judge its own writing. The critic agent grades against a written rubric and rejects a real share of what the drafter produces. It recently killed a draft of mine that claimed a start date the project’s own files contradicted. Self-review is not review.

It can’t see. Generated illustrations go to a separate auditor agent, which has rejected work I had already approved myself.

It has no taste. It has my written doctrine, and doctrine trails judgment by weeks.

It handles API-less platforms badly. Roughly half the actions I want are locked behind partner-gated APIs, which leaves an agent driving a real browser: slower, more fragile, one UI change from breaking.

And it is one person’s system, deliberately. Four documents. One lead. No team has ever used it, so nothing here is evidence about multi-user behaviour, and I won’t pretend otherwise until it is.

Why publish the failure rate

Because “we deployed agents” carries no information. My feed is full of agentic announcements and nearly empty of numbers.

Nine of forty-six runs avoided the bug: seven finished, two correctly refused to act. A bad default on good bones — and the reason I can name the default is that the bones write everything down.

What I don’t know yet is whether the rate improves or the failures just change species. The timeout is fixed. My suspicion is that the next 46 runs fail in ways that are actually about judgment rather than plumbing, and those will be much harder to read off a table. I have no evidence for that suspicion. It’s just what usually happens once the boring bugs are gone.