A dead embedded Lemonade's leftover state file hijacks every client to a port with nothing on it
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 76/100
Research direction
Start in src/gaia/llm/lemonade_client.py at _embedded_lemonade_url() and _read_embedded_lemonade_state(), then compare the process checks in src/gaia/llm/lemonade_embedded.py, especially EmbeddedLemonade.status(). Add a regression test for a state.json with a dead pid and verify the workflow dials the URL prepared by its setup step.
Written by the indexing model from the issue text.
Description
A dead embedded Lemonade keeps redirecting every GAIA client to its old port, so a perfectly healthy server on the default port looks unreachable.
Start gaia lemonade embedded, then have it die — killed, crashed, machine rebooted. The state file it left behind still names the port it once bound, and every client reads that file ahead of the default. From then on gaia llm, the Agent SDK, and the API server all dial a port with nothing on it and report Lemonade as down, while the real server answers on 13305. Nothing tells the user why; the only cure is knowing to delete a file they have never heard of.
This is currently red in CI. Test Agent SDK on Windows (Lemonade Integration) health-checks Lemonade on 13305, passes, and then every test in the run fails connecting to port 59939 — a stale embedded port on the persistent self-hosted runner. It has failed the same way on at least three unrelated branches (kalin/ui-design-language, claude/ui-tick-session-lock, claude/ui-fresh-cancel-event), so it is not any one PR's doing.
Suggested fix: don't let the state file win unless its process is actually alive. The embedded manager already knows how to decide this; the client just doesn't ask.
🔍 Technical details
_embedded_lemonade_url() (src/gaia/llm/lemonade_client.py:66) returns http://localhost:<port> straight from ~/.gaia/lemonade/state.json whenever the port parses as an integer. _read_embedded_lemonade_state() (:81) validates only that the port is an int in 1..65535 — no pid check, no health probe, no timestamp — and _get_lemonade_config() (:114) uses that in preference to DEFAULT_LEMONADE_URL whenever LEMONADE_BASE_URL is unset.
The asymmetry is the bug: state.json already records a pid (lemonade_embedded.py:964), and EmbeddedLemonade.status() (:765) does the full job — health probe, then _daemon_alive(pid), and _clear_state() when the state is incomplete. The client-side reader bypasses all of it.
Two candidate fixes:
- Have
_read_embedded_lemonade_state()require_daemon_alive(state["pid"])before returning the state, falling back toDEFAULT_LEMONADE_URLotherwise. - Or have the embedded manager clear
state.jsonon a non-graceful exit, which it cannot do for aSIGKILL/reboot — so the reader-side check is the one that actually closes the hole.
Evidence from run 36085092147:
Lemonade already healthy on port 13305 -- reusing persistent server.
⏳ Waiting for LLM server at http://localhost:13305...
✅ Server health check passed
...
LemonadeClientError: Failed to load model 'Gemma-4-E4B-it-GGUF' on http://localhost:59939/api/v1:
[WinError 10061] No connection could be made because the target machine actively refused it
Unblocking CI in the meantime means deleting C:\Users\Administrator\.gaia\lemonade\state.json on actions-runner-01, or exporting LEMONADE_BASE_URL in the workflow so the stale file cannot win.
A regression test wants both halves: a unit test that a state.json naming a dead pid does not change the resolved base URL, and a workflow-level assertion that the URL the tests dial is the one the setup step readied.
- Dominant language
- Python
- Stars
- 1.6k
- Forks
- 169
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 511
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from amd/gaia
-
bug p2
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
docs: bare amd-gaia.ai links outside src/gaia 404 (issue template, install-ui scripts, CLAUDE.md)Open
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
BasedHardware/omi#20271 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 92/100
openai/openai-cookbook#3153 ·
Maintainers usually reply within 1 day
-
cvss-severity:high devguard l3montree-cybersecurity/devguard/devguard pkg:golang/github.com/l3montree-dev/devguard risk:low state:open
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
l3montree-dev/devguard#3146 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
bug confirmed issue
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
open-webui/open-webui#31849 · 2 comments ·
Maintainers usually reply within 1 day