Troubleshooting
Begin with the narrowest check that distinguishes host ingress from container runtime. Keep .env unread and never use the rendering form of Compose configuration.
Compose validation fails
cd ~/dev/lobe
sudo -n docker compose config --quiet- if this fails:
- check names and placeholders against
.env.example - confirm
.envexists and remains mode0600 - do not run the non-quiet rendering command to inspect interpolation
- check names and placeholders against
- if validation passes but startup fails:
- run
sudo -n docker compose ps -a - inspect only the affected service with
sudo -n docker compose logs --tail=100 <service>
- run
Lobe remains pending or unhealthy
Lobe is health-ordered behind PostgreSQL, Redis, RustFS, and successful rustfs-init completion.
sudo -n docker compose ps -a
sudo -n docker compose logs --tail=100 lobe
sudo -n docker compose logs --tail=100 postgresql redis rustfs rustfs-init- PostgreSQL must pass
pg_isready -U postgres. - Redis must answer
redis-cli ping. - RustFS must answer its internal
/healthcheck. rustfs-initmust exit0; a nonzero result blocks Lobe startup.- Lobe’s own healthcheck fetches
http://127.0.0.1:3210/from inside the container.
Do not delete an authoritative volume to clear a health failure.
LiteLLM is unreachable
The valid route is container DNS over external network lllm_default, not a host gateway.
- expected proxy:
http://lllm-proxy:4000/v1 - expected key: the scoped virtual key stored as
OPENAI_API_KEY - expected aliases:
fast,oss-120b,free
sudo -n docker network inspect lllm_default >/dev/null
sudo -n docker exec lobe node -e "fetch('http://lllm-proxy:4000/health/readiness').then(r=>{console.log(r.status);process.exit(r.ok?0:1)}).catch(e=>{console.error(e.message);process.exit(1)})"- name-resolution or connection failure:
- verify
lllm-proxyexists onlllm_default - verify only the Lobe service needs the external network
- verify
403for one of the three approved aliases:- verify the
lobevirtual key scope andOPENAI_MODEL_LIST=-all,+fast,+oss-120b,+free
- verify the
- success for an unlisted model:
- treat as a scope regression; the verified contract is rejection with
403
- treat as a scope regression; the verified contract is rejection with
Never substitute the LiteLLM master key. Use the redaction-safe probes in verification.
OIDC discovery or callback fails
sudo -n docker exec lobe node -e "fetch('https://auth.loca.zone/.well-known/openid-configuration').then(r=>{console.log(r.status);process.exit(r.ok?0:1)}).catch(e=>{console.error(e.message);process.exit(1)})"Check the exact client contract:
- client ID
lobe - issuer
https://auth.loca.zone - redirect URI
https://lobe.loca.zone/api/auth/callback/authelia - scopes
openid,profile,email - authorization code flow
client_secret_basic- policy
one_factor - implicit consent
Interpret authorization markers directly:
invalid_client: client ID, secret pair, or token authentication mismatchinvalid_redirect_uri: callback does not exactly match the registered URIinvalid_scope: requested scopes drifted from the registered set- account lacks usable identity after callback: verify the Authelia identity still emits a non-empty email claim
Do not enable email and password login as a workaround. Do not expose either plaintext client secret or its digest.
Desktop or API receives an Authelia HTML redirect
This is an edge-gate regression, not the native OIDC flow.
deploy/lobe.nginx.confmust contain noauth_requestonlobe.loca.zone.- Authelia edge access-control rules must not name
lobe.loca.zone. - Browser sign-in should reach Authelia only after LobeHub initiates OIDC.
Restore the application-owned identity boundary described in auth-model.
Upload or attachment fails
curl -fsS http://127.0.0.1:52101/health >/dev/null
sudo -n docker compose ps -a rustfs rustfs-init
sudo -n docker compose logs --tail=100 rustfs rustfs-initCheck:
S3_ENDPOINTis exactlyhttps://s3.lobe.loca.zonewith no path suffix- path style is enabled
- bucket is
lobe - S3 ACL mutation is disabled
- RustFS console remains disabled
- nginx preserves Host and Origin, leaves the object path unchanged, disables request buffering, and allows up to
128m - browser requests use HTTPS and show no CORS, mixed-content, or
413error
The bucket policy intentionally makes uploaded object URLs anonymously readable. A successful anonymous read is not evidence of a write-permission leak; writes still require a valid signature.
Streamed replies stall
- application loopback healthy but public stream stalls:
- inspect the
lobe.loca.zonenginx vhost - require
proxy_buffering offandproxy_cache off - require
86400-second proxy read and send timeouts - preserve HTTP/1.1 upgrade and forwarding headers
- inspect the
- both loopback and public requests fail:
- inspect Lobe and dependency status before nginx
Search fails
SearXNG is private and resolves as http://searxng:8080 on lobe-network.
sudo -n docker compose ps searxng
sudo -n docker compose logs --tail=100 searxngThe tracked settings file remains read-only. Its public placeholder secret_key is overridden by SEARXNG_SECRET from .env; do not reveal the override value while diagnosing.
Wiki fails while the app is healthy
The wiki is static and does not depend on Compose.
- confirm the wiki
currentsymlink resolves to a completeddist-*directory - confirm that release contains
index.html - rerun the wiki lint and atomic build procedure
- a missing route must return
404, not a fallback document
Certificate mismatch
One certificate lineage named lobe.loca.zone serves all three TLS vhosts. Its SAN set must include:
lobe.loca.zonewiki.lobe.loca.zones3.lobe.loca.zone
If one host presents a different set, inspect the installed nginx vhost and the lineage paths before reload. The verified lineage expires 2026-11-27.