vibeapp.win

What brokeUpdated 3 October 2026

Local LLM calls had no timeout, so one hung model could hang a request forever

A code review on 2 July 2026 found two problems in one of our small apps. Its calls to local LLM servers had no timeout, and it wrote its JSON files in place, so a crash mid-write could corrupt them. We added explicit timeouts (120 s, 5 s for the model list) and switched to atomic tmp-and-rename writes.

The short version

What went wrongCalls to local LM Studio and Ollama servers had no timeout, so a hung model could hang a request forever. JSON files were also written in place, so a crash mid-write could corrupt them.

How we found itA code review on 2 July 2026 found both problems. The record does not say whether either hit a real user.

The rule nowGive every external call an explicit timeout, even local ones. Write files atomically: write to a temporary file, then rename it into place.

This post documents something Claude got wrong. The claim rests on a commit or a file, not on memory. All of Claude's mistakes

This one was found by reading the code. On 2 July 2026 we ran a code review of one of our small apps. The review turned up two problems with the same root cause: the code assumed things outside its control would always behave.

The first problem was that calls to the local language model servers (LM Studio and Ollama) had no timeout. The second was that the app wrote its JSON files in place. A crash in the middle of a write could leave a broken file behind.

Who made the mistake

Henning writes no code himself, so the missing timeouts and the in-place writes were Claude’s. The commit that fixes both problems describes them as findings from a code review. It does not say who did the review.

What was wrong with the LLM calls

The app sends some work to a local model, for example a “scan” request. The request goes to a local LM Studio or Ollama server.

Without a timeout, the request waits forever if no answer comes. The project log for that round says it plainly: a hung LM Studio previously let the scan request hang forever.

The material does not say whether this ever happened to a real user or was spotted only in the code. It is listed among the review findings, so we treat it as a finding, not an incident.

What was wrong with the JSON files

The app keeps some state as JSON files on a volume.

If the process crashed partway through a write, the file could be corrupted. The project log says this was fixed so that a crash in the middle of a write can no longer corrupt the files on the volume.

The fix

Both fixes are in the same commit, dated 2 July 2026.

Timeouts. Every call to LM Studio and Ollama now has an explicit timeout of 120 seconds. The call that fetches the list of available models gets a 5-second timeout. The commit message says the timeouts are on all LM Studio and Ollama calls, so that a hung LM Studio no longer hangs the request forever. The split makes sense. Generating an answer can legitimately take a while. Listing models should be almost instant, so if it isn’t, something is wrong and the app should say so quickly. The material doesn’t explain how the 120-second figure was chosen, so we won’t guess.

Atomic writes. The app’s JSON data files are now written to a temporary file first and then renamed into place. A rename replaces the old file in one step, so a reader sees either the complete old file or the complete new one, never a half-written one. In the same change, reads became tolerant of a UTF-8 byte order mark at the start of the file.

A related change in the same commit: the client-side function that fetches served results now throws on server errors, so the UI shows a real error message instead of failing quietly. That matters more once timeouts exist. A timeout that ends in silence is only a little better than a hang.

How it was checked

The commit lists what was run before it went in:

  • a new smoke test in CI that boots the server against a temporary cache directory and runs 8 checks
  • 14 Playwright end-to-end checks, plus a sync scenario (listed as 5)
  • a production build
  • a local run on Express 5, which the same commit upgraded to

None of these is listed as a test of the timeout itself. The commit does not describe a test that simulates a hung model server or a crash mid-write. The timeouts and atomic writes are covered by the general checks, not by a dedicated one.

That same review round also fixed a preferences sync bug and moved the app to Express 5. Those are separate stories.

Why this kind of bug survives

Both problems are invisible when things work. A local model that answers in two seconds never shows that it could have hung forever. A file write that takes a millisecond is almost never interrupted. These are the cases normal use doesn’t test, and they are the ones that turn a slow dependency into a frozen app, or a restart into lost data. Reading the code found them.

The rule

Every external call gets an explicit timeout, including calls to services on the same machine. “Local” does not mean “always answers”. Pick the timeout to fit the call: long for generation, short for something that should be instant.

Any file that can be read while it is being written is written atomically: write to a temporary file, then rename it into place.

Corrections

  1. Attribution corrected: an earlier version said the material did not show who wrote the code and did not put the mistake on Claude. Henning writes no code himself; the code was written by Claude.