My n8n lead agent looked fine until I realized it was dying at the Apollo, HubSpot, and JSON handoffs
At 2:13 a.m. my n8n lead-enrichment flow marked the same prospect as enriched twice, Apollo returned HTTP 200 with nothing useful, HubSpot threw 423 Locked, and GPT-5 kept confidently retrying bad JSON.
The annoying part is that the workflow looked healthy at a glance. Green checks in n8n. No dramatic stack trace. Just a slow drip of duplicate contacts, half-filled records, and retries that made the whole thing more expensive without making it more correct.
This is not an LLM intelligence problem. It is a contract-design problem, and a lot of n8n builders are blaming GPT-5 for bugs caused by Apollo edge cases, HubSpot write behavior, and sloppy JSON validation. My strong opinion after debugging this: strict JSON contracts with idempotency keys beat “let the model fix it on retry” every time.
I originally thought the model was the weak link. That was the false diagnosis. The real failures were happening in the handoffs between n8n, Apollo’s enrichment API, HubSpot’s contact write API, and the model’s JSON output.
The symptom looked like flaky AI
The flow was simple on paper:
- Pull a new lead into n8n
- Send the lead to Apollo for enrichment
- Ask GPT-5 to normalize the result into the fields I wanted
- Write the contact into HubSpot
- Retry if anything failed
That sounds reasonable until step 2 returns something technically successful but operationally useless, step 3 turns partial input into confident-looking JSON, and step 4 hits a temporary lock right when your retry logic is least careful.
So the first symptom was not “the agent crashed.” The first symptom was worse: the agent kept running.
Why does Apollo return 200 when the lead is still unusable?
This was the first ugly surprise. Apollo can return HTTP 200 even when the enrichment result does not contain enough identity data to be useful for the next step.
If your n8n branch only checks the status code, the workflow moves on as if the lead is enriched. Then GPT-5 gets a payload with missing fields, tries to be helpful, and emits JSON that is structurally valid enough to pass a casual glance but semantically wrong for your HubSpot write.
That is where people say, “the model hallucinated.” Sometimes it did. But in my case the bigger problem was that I asked the model to normalize a record that Apollo never really enriched in the first place.
My rule now is simple: Apollo does not count as successful unless the payload contains the exact fields the next step requires. HTTP 200 is not success. A usable person or company record is success.
That one change removed a huge amount of fake progress from the workflow.
What should n8n do when HubSpot returns 423 Locked?
This was the second ugly surprise. HubSpot can return 423 Locked for a short window, often around 2 seconds. If your workflow treats that like a generic failure and immediately retries the same write, you can create the exact mess you were trying to avoid.
My bad version of this flow did three things wrong:
- It retried too fast
- It retried without a real idempotency key
- It let the fallback path create a new contact instead of proving whether the first write eventually landed
That is how you get duplicate contacts and confusing audit trails.
The better pattern is boring, which is why it works:
- Use email as the primary unique key when possible
- Store an idempotency key in n8n before the HubSpot write
- On 423 Locked, wait a little longer than your instinct says
- Re-check HubSpot before retrying a create path
- Separate “retry the same write” from “attempt a new create”
This is where I stopped blaming GPT-5 entirely. No model can rescue bad write semantics.
The false diagnosis was “just prompt it better”
My first fix was the classic one: tighten the prompt, ask for cleaner JSON, add more examples, and tell the model not to invent missing fields.
That helped a little. It did not solve the real problem.
Prompting harder is the wrong first move when Apollo is returning thin records and HubSpot is temporarily locking writes. You are polishing the middle of the pipeline while the ends are lying to each other.
If I had to pick one loser pattern, it is this: “let the model fix it on retry.” That pattern burns time, burns tokens, and hides the real bug. The winner is strict validation before and after every named service call.
The fix was less agentic than I wanted
I wanted a clever lead-enrichment agent. What actually worked was a more disciplined workflow.
The fixes were not glamorous:
- Validate Apollo payloads against required fields before any model call
- Use Structured Outputs instead of “please return valid JSON” whenever possible
- Reject partial JSON instead of trying to salvage it downstream
- Add idempotency keys before HubSpot writes
- Treat HubSpot 423 Locked as a timed retry case, not a generic error
- Log every payload transition between n8n, Apollo, GPT-5, and HubSpot
The most important change was deciding that partial success is failure. Once I stopped letting weak Apollo results and half-valid model output sneak through, the workflow got much quieter.
Why this gets expensive fast if you pay per token
This part matters for anyone running agents in n8n, Make, Zapier, OpenClaw, or custom automations at real volume.
When a workflow bounces across Apollo, HubSpot, and multiple model calls, debugging is not a single request. It is a chain of retries, schema checks, reformats, and replay runs. If you are paying per token, reliability work gets punished twice: once in development, and again in production when edge cases trigger extra model calls.
That pricing model changes behavior. Teams become conservative about testing. They avoid aggressive replay. They hesitate to add validation loops because every safeguard has a visible marginal cost.
Flat-rate compute changes that. If your API layer can route across models and absorb heavy retry and testing behavior without surprise bills, you can afford to build the safer version of the workflow instead of the cheapest-looking one. For teams running lead agents all day, predictable cost is not just a finance benefit. It changes how seriously you can treat reliability.
What should people building in n8n, Make, or Zapier stop doing?
Stop treating status-code success as workflow success.
Stop asking GPT-5 to paper over missing Apollo data.
Stop retrying HubSpot writes without idempotency.
Stop calling malformed or partial JSON “close enough.”
And stop assuming the expensive part of the workflow is the smart part. In my experience, the real damage happens in the boring places: the API response you did not validate, the lock you retried too quickly, and the duplicate write you did not make idempotent.
That was the lesson for me. My n8n lead agent did not need a smarter model nearly as much as it needed stricter contracts between Apollo, GPT-5, HubSpot, and the workflow itself.
If you are seeing “flaky AI” in lead enrichment, look there first.