You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Running the native macOS CLI (macos-arm64/needle) in serve mode against the README's quickstart tools file (get_weather + set_thermostat) causes the process to enter a spin loop inside needle_complete on the very first POST /complete request. The connection is never accepted for subsequent requests, no response is written, and the process pegs multiple cores indefinitely.
cd~/Models/cactus-needle2
./needle --serve --port 8082 --tools /tmp/needle-tools.json &# logs only the startup line — nothing further is ever written
curl -X POST http://127.0.0.1:8082/complete -d '{"input":"what is the weather in Lagos"}'# connection times out, process never returns
Observations
The log file (needle-server-YYYYMMDD.log) only contains the startup banner — no request lines, so the request never reaches a serialisation path that produces output.
lsof -p <pid> shows the listener is bound, but the inbound TCP connection is accepted and then sits with zero bytes read/written until I kill the process. There is exactly one closed stale connection in the FD table after several minutes.
RSS stays at ~14.6 MB the entire time — no model weights are being paged in. This is purely a CPU spin, not an inference pass.
sample <pid> shows the main thread stuck entirely inside needle_complete:
1177 Thread_93436044 DispatchQueue_1: com.apple.main-thread (serial)
1177 start (in dyld)
1177 needle_complete (in needle) + 4248
1176 ??? (in needle) load address 0x102988000 + 0xb730
1176 ??? (in needle) load address 0x102988000 + 0x61e8c
1176 ??? (in needle) load address 0x102988000 + 0x447c
781 ??? (in needle) load address 0x102988000 + 0x46944
781 ??? (in needle) load address 0x102988000 + 0x496b8
210 ??? (in needle) load address 0x102988000 + 0x5754c
The recursion depth in needle_complete and absence of any symbol resolution confirms this is the grammar-constrained decode loop. 1177/1177 samples are inside it — not a request-handling thread.
The bug burns ~380% CPU continuously until the process is killed (verified over a 24h run). No timeout, no log line, no way for the operator to know the request will never complete.
Issue #51 was a Python-package bug (shared needle_init engine with stale tools) that produced a wrong-but-bounded response — the model reasoned about a description field that wasn't in the schema, then truncated with token budget exhausted. The same get_weather/set_thermostat schema mismatch that produced wrong-tool reasoning in #51 may be putting the native CLI's constrained decode loop into a state with no grammar-accepting continuation, so the engine retries forever instead of falling back to a refusal response like the Python path does.
Summary
Running the native macOS CLI (
macos-arm64/needle) in serve mode against the README's quickstart tools file (get_weather+set_thermostat) causes the process to enter a spin loop insideneedle_completeon the very firstPOST /completerequest. The connection is never accepted for subsequent requests, no response is written, and the process pegs multiple cores indefinitely.Environment
/Users/tom/Models/cactus-needle2/needle(14,610,568 bytes, matchesCactus-Compute/needle2macos-arm64/needlebyte-for-byte, dated 2026-09-07)--serve --port 8082 --tools /tmp/needle-tools.jsonget_weather/set_thermostatschemas from the Quickstart section ofREADME.md(see Thermostat example from README truncates with "token budget exhausted" #51 for context)Reproduction
Observations
needle-server-YYYYMMDD.log) only contains the startup banner — no request lines, so the request never reaches a serialisation path that produces output.lsof -p <pid>shows the listener is bound, but the inbound TCP connection is accepted and then sits with zero bytes read/written until I kill the process. There is exactly one closed stale connection in the FD table after several minutes.sample <pid>shows the main thread stuck entirely insideneedle_complete:needle_completeand absence of any symbol resolution confirms this is the grammar-constrained decode loop. 1177/1177 samples are inside it — not a request-handling thread.Likely relationship to #51
Issue #51 was a Python-package bug (shared
needle_initengine with stale tools) that produced a wrong-but-bounded response — the model reasoned about adescriptionfield that wasn't in the schema, then truncated withtoken budget exhausted. The sameget_weather/set_thermostatschema mismatch that produced wrong-tool reasoning in #51 may be putting the native CLI's constrained decode loop into a state with no grammar-accepting continuation, so the engine retries forever instead of falling back to a refusal response like the Python path does.Expected
Either:
refuse/truncatedJSON response matching the Python package's behaviour (preferred, matches Thermostat example from README truncates with "token budget exhausted" #51's resolution), orActual
Process spins at ~380% CPU, never logs anything, never writes a response, never returns from
needle_complete. Killed only bySIGKILL.Workaround
None observed. The CLI appears unusable with the README's example tools file. Limiting this to the Python package is not a documented constraint.