Troubleshooting¶
The things that go wrong, and how to tell which. Each entry says what to look for and the command that names the fix — spinloop's errors are written to say that.
The agent ignores the model¶
You applied a selection and the agent still runs something else.
- What does the harness actually hold?
spinloop harness showreads the agent's config back and reports each configured provider and model. If the selection isn't there, the apply did not land where you think it did. - Which harness was configured, and which is launching? Every command
resolves the harness in this order:
--harness/-H,SPINLOOP_HARNESS, your stored default, opencode. A-H piapply with an opencode launch configures one and runs the other.spinloop harness configprints the active harness and where that choice came from. - On opencode,
addsets the model as the default. Pi has no default-model setting — after an apply, pick the model with/modelin Pi. - You started the agent yourself, not through
spinloop code. The key is a reference to an environment variable, not a value in the config.spinloop harness openandcodepass the keys they can resolve; a hand-started agent gets nothing unless you set the variables in its environment.
The engine won't start¶
spinloop serve (or a wake) fails at launch.
- The engine is not installed.
serveruns the engine; it does not ship one.llama-servermust be on yourPATH(brew install llama.cpp); oMLX is found on thePATHor at/Applications/oMLX.app/Contents/MacOS/omlx-cli;mtplxon thePATH. - The port is taken. The engine binds the
BASEURLaddress (or the engine's own default). ChangeBASEURLin the Spinloop, or stop whatever holds the port. - A
PRESETwith several sections and noALIASis an error, naming the sections — name one. Presets are written in one engine's flag vocabulary and are not portable between engines. --dry-runshows the command that will run. Read it before debugging anything else.
The context is smaller than asked for¶
llama.cpp's --ctx-size is a total KV-cache budget it divides across
--parallel slots. spinloop compensates: CONTEXT 128k + PARALLEL 2
renders --ctx-size 256000 --parallel 2, so each request still gets 128k. A
PRESET's own ctx-size, left unstated by the Spinloop, is not
retroactively scaled — the preset is trusted to account for its own slots.
vLLM and MTPLX share one pool across requests, so their context is never
scaled; see spinloop serve.
A key is missing or not picked up¶
- Keys are looked up in a
.envbeside theSpinloopbeing applied (or in the current directory for a command that takes no Spinloop), then your shell environment. A project's key travels with the project that way. - A provider that requires a key tells you which variable to set when the lookup comes up empty — set the one it names.
- Local providers on localhost (Ollama, llama.cpp) need no key; Bedrock uses your AWS credentials.
The daemon refuses to start, or shows crashed¶
- A non-loopback listen with no token refuses to start, naming the three
ways to supply one (
--api-token-file,SPINLOOP_API_TOKEN,--api-token). Giving two at once is an error, not a silent precedence. - A crash is reported, never auto-restarted. The state says
crashed; readdaemon/engine.logunder spinloop's config directory, then start the engine again through the API.
A remote endpoint won't come up¶
- The control plane is not deployed. Every
remotecommand that acts on an endpoint needsspinloop remote bootstrapto have run once per account; a missing control plane says so. An older control plane that lacks a feature says to re-runbootstrapto add it. - The AMI is not baked.
spinloop remote bakeonce per engine, and it waits until the AMI is available. - A cold start takes about ten minutes.
startprints its progress on stderr;--timeout(default 15m) bounds the wait.statusandlogsanswer while it boots and after it is gone — logs are readable even from a terminated instance. - Quota. Bootstrap needs enough GPU vCPU quota for a later launch; a launch that can't get an instance reports the AWS error.
A fleet row is wrong, or a node won't answer¶
config-erroron akind: remoterow means the environment is not registered on this machine —spinloop remote deploy --env <name>(orspinloop fleet deploy) writes itsremote.json.- A node's token is not in your shell. The fleet file names the
variable (
tokenEnv), never the value. Set the variable the row names, from the.envbeside the fleet file or your environment. - Host and port name the daemon, not the engine. If the daemon answers but
routing can't reach the engine, the engine is bound to loopback — the
failure says so. Bind it to a reachable address or declare an
engineblock in the fleet file. - A down node never blanks the view. It is reported in its place, the way every fleet view reports it — the rest of the fleet keeps answering.
The gateway refuses a request¶
- 401 — the caller's token. It is the gateway's token (the three sources the daemon's token follows), not any node's.
- Refused, naming a node — nothing serves the model and no candidate may
be woken (its own
wake, or the file's, is off). The failure names the node that would have woken and thespinloop fleet start <node>command that would start it. - An undeployed remote environment is never a candidate — it has nothing
to serve yet; choosing what to deploy is
spinloop remote deploy's call. - 404 naming other paths — the gateway serves
/health,/v1/models,/v1/chat/completions,/v1/completions, and/v1/fleet, and says so.
spinloop hf inferred the wrong thing¶
The narration on stderr says what was chosen and why — provider and why,
quantisation and the alternatives, context and its source. Override any of it:
-p for the provider, -q for the quantisation, -c for the context, -a
for the alias. A quantisation the repo does not have fails listing the ones it
does.
Still stuck¶
The source is on GitHub — open an
issue with the command you ran and its output. --dry-run on serve,
spinloop harness show, and the daemon's daemon/engine.log are the three
facts that answer most questions.