Skip to content

fix(providers): use 127.0.0.1 instead of localhost for local LLM URLs#3112

Merged
houko merged 1 commit into
mainfrom
fix/ollama-localhost-ipv6
Apr 25, 2026
Merged

fix(providers): use 127.0.0.1 instead of localhost for local LLM URLs#3112
houko merged 1 commit into
mainfrom
fix/ollama-localhost-ipv6

Conversation

@houko

@houko houko commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Summary

On dual-stack hosts (notably macOS), localhost resolves to both ::1 and 127.0.0.1 with IPv6 tried first. Local LLM servers (Ollama / vLLM / LM Studio / Lemonade) installed via the standard scripts bind IPv4 only, so reqwest's first connection attempt to [::1]:<port> is refused instantly. Happy Eyeballs fallback to IPv4 isn't reliably triggered for connection-refused (vs. timeout), so the probe fails outright and the daemon spams:

WARN Configured local provider offline provider=ollama error="error sending request for url (http://localhost:11434/api/tags)"

…even though curl http://localhost:11434/api/tags works fine (curl explicitly does the IPv6→IPv4 fallback).

Repro

$ lsof -iTCP:11434 -sTCP:LISTEN
COMMAND  PID  USER  FD  TYPE  NODE NAME
ollama   ...  ...   5u  IPv4  TCP localhost:11434 (LISTEN)   ← IPv4 only

$ cat /etc/hosts | grep localhost
127.0.0.1  localhost
::1        localhost

The TCP-level reachability check at kernel/mod.rs:1754 already uses 127.0.0.1 directly (and succeeds), but the URL stored in provider_urls.ollama was http://localhost:11434/v1, so subsequent reqwest calls fail. This PR brings the URL strings in line with the reachability check.

Changes

Production code:

  • PROVIDER_REGISTRY defaults for ollama, vllm, lmstudio, lemonade (librefang-llm-drivers)
  • Embedding driver fallback URLs for the same three providers (librefang-runtime/embedding.rs)
  • Auto-detected ollama URL injected into provider_urls (librefang-kernel/kernel/mod.rs)
  • The standalone Ollama detect probe (librefang-api/routes/providers.rs::detect_ollama)
  • Example URLs in the init config template (librefang-cli/templates/init_default_config.toml)

Existing test fixtures that happen to use localhost as an arbitrary input string are intentionally left alone (they're not asserting the default URL constant). The two model_catalog.rs tests that DO assert default URLs (test_set_provider_url, test_apply_url_overrides) still load from the live librefang-registry repo via resolve_home_dir_for_tests, so they are not affected by this PR — they will need updating in tandem with the registry-repo PR (see below).

Follow-up needed

The runtime probe URL (the one that actually triggered the warning the user reported) comes from ~/.librefang/registry/providers/ollama.toml, which is synced from the librefang-registry repo. A matching PR is needed there to flip those base_url fields from http://localhost:... to http://127.0.0.1:.... After both land, existing installs will pick up the fix on their next registry sync.

Test plan

  • CI green (workspace build + tests + clippy zero-warnings)
  • On a macOS host with Ollama running and no provider_urls.ollama override in config.toml: start daemon, confirm no Configured local provider offline warning and ollama appears as reachable in the model catalog
  • Manual: send a chat message to an ollama-backed agent end-to-end

On dual-stack hosts (notably macOS), `localhost` resolves to both ::1
and 127.0.0.1 with IPv6 tried first. Local LLM servers (Ollama, vLLM,
LM Studio, Lemonade) typically bind IPv4 only, so the IPv6 attempt
returns connection-refused immediately and Happy Eyeballs fallback
isn't reliably triggered — leading to spurious "Configured local
provider offline" warnings even when the server is running and
reachable via curl.

Changes the hardcoded fallback URLs in PROVIDER_REGISTRY, embedding
driver fallback, kernel auto-detect injection, the ollama detect
route, and the init config template comments.

Note: the user-facing TOML in `~/.librefang/registry/providers/*.toml`
comes from the separate librefang-registry repo and needs a matching
PR there to fully eliminate the warnings on existing installs.
@houko
houko merged commit a5ce4c4 into main Apr 25, 2026
19 of 22 checks passed
@houko
houko deleted the fix/ollama-localhost-ipv6 branch April 25, 2026 09:57
@github-actions github-actions Bot added area/runtime Agent loop, LLM drivers, WASM sandbox area/kernel Core kernel (scheduling, RBAC, workflows) ready-for-review PR is ready for maintainer review labels Apr 25, 2026
houko added a commit to librefang/librefang-registry that referenced this pull request Apr 25, 2026
…73)

On dual-stack hosts (notably macOS), `localhost` resolves to both ::1
and 127.0.0.1 with IPv6 tried first. Local LLM servers (Ollama, vLLM,
LM Studio) installed via the standard scripts bind IPv4 only, so the
IPv6 connection attempt fails immediately and Happy Eyeballs fallback
to IPv4 isn't reliably triggered for connection-refused errors,
producing spurious "Configured local provider offline" warnings in
the daemon even when the server is up and reachable via curl.

Companion to librefang/librefang#3112 which fixes the hardcoded URL
constants in the main repo. After both land, existing installs pick
up the fix on their next registry sync.
@github-actions github-actions Bot added size/S 10-49 lines changed and removed ready-for-review PR is ready for maintainer review labels Apr 25, 2026
houko added a commit that referenced this pull request Apr 25, 2026
…ault change (#3118)

PR #3112 changed the local provider defaults from `http://localhost:`
to `http://127.0.0.1:` in PROVIDER_REGISTRY but didn't update the two
test assertions that pinned the old default. Main has been red since
that landed:

  FAIL model_catalog::tests::test_apply_url_overrides
    left:  "http://127.0.0.1:1234/v1"
    right: "http://localhost:1234/v1"
  FAIL model_catalog::tests::test_set_provider_url
    left:  "http://127.0.0.1:11434/v1"
    right: "http://localhost:11434/v1"

Update the two assertions. test_set_provider_url_unknown still uses
`localhost:9999` because it's exercising user-supplied URL passthrough
(not the default), unrelated to #3112.
@houko houko mentioned this pull request Apr 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/kernel Core kernel (scheduling, RBAC, workflows) area/runtime Agent loop, LLM drivers, WASM sandbox size/S 10-49 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant