Field note · DGX Spark

Detecting which inference engine owns a port: vLLM vs. llama.cpp

Detection that infers the engine from the port number breaks the moment either engine moves. Moving llama.cpp onto the port normally used by vLLM mislabeled it, and downstream code silently wrote null. /props is a clean discriminator: llama-server serves it, and the vLLM OpenAI-compatible server has no such route and returns 404. A second gotcha in the same detour: docker ps --filter publish= does not match a container using host networking.

Hardware
NVIDIA DGX Spark · GB10 (SM121) · aarch64 · 128 GB unified
Software
vLLM OpenAI-compatible server (port 8000) and llama.cpp llama-server (port 8001) on the same host

Symptom

This host's convention is vLLM on port 8000 and llama.cpp on port 8001. This isn't a bug specific to that convention or to either engine — it will bite anyone who runs two inference engines and identifies them by which port they happen to be on. It bit here when llama.cpp was briefly moved onto port 8000, and the model-registration script mislabeled it immediately, because detection inferred the engine from the port, not from anything the server itself said:

# Check vLLM (port 8000)   <-- labels ANYTHING on 8000 as vllm

That's not cosmetic. Downstream code branched on the resulting provider value to scrape --max-num-seqs from a vLLM process that no longer existed on that port, and wrote null.

Fix: ask the server, do not guess from the port

/props is a clean discriminator. llama-server serves it — build_info, chat_template, slots — and the vLLM OpenAI-compatible server has no such route at all:

if curl -s "http://127.0.0.1:${port}/props" | jq -e '.build_info' >/dev/null 2>&1; then
    provider="llamacpp"
else
    provider="vllm"
fi

A second gotcha in the same detour

docker ps --filter publish=8000 doesn't match a container running with host networking — the vLLM container here does, so its Ports column is empty and the filter finds nothing, even while vLLM is plainly listening on that port. Match on the container name instead.

The port move itself was reverted; nothing in the local tooling actually hardcoded 8000. The one field consumers read is rewritten on every model switch, so it follows whichever server is actually running rather than pinning a port — which is exactly why detecting the engine from the port number was never a safe shortcut to begin with.

Status
resolved
First seen
August 26, 2026