Skip to main content

Start here

These four commands identify most problems:

Installation

The environment schema is validated at startup, so a missing or invalid value stops the process immediately.
Common causes:
  • BETTER_AUTH_SECRET or SETTINGS_ENCRYPTION_KEY shorter than 32 characters
  • BASE_URL not a valid absolute URL
  • DATABASE_URL missing or malformed
Migrations cannot reach the database. Confirm the database pod is ready and the connection string resolves:
With the bundled database, the password inside DATABASE_URL must match POSTGRES_PASSWORD in the same Secret.
The application is up but the database query failed. Check credentials, connection limits, and whether the database pod restarted.
The storage class is missing or cannot provision ReadWriteOnce volumes.
Confirm the ingress class matches your controller, DNS points at it, and the Service has endpoints:

Authentication

The most common misconfiguration. publicUrl does not match the URL in the browser, so the session cookie is scoped to the wrong host and rejected. Align publicUrl, ingress.host, and DNS, including https:// versus http://.
The setup transaction did not complete. Check logs for a database error, and query the state:
The token must match SETUP_CLAIM_TOKEN in the running pod’s environment exactly. If you changed the Secret, restart the Deployment so it is re-read.
The provider’s registered redirect URI must be exactly https://<publicUrl-host>/api/auth/oauth2/callback/<provider-key>.
BETTER_AUTH_SECRET changed. Restore the original value to preserve sessions; otherwise users simply sign in again.

Workspaces

The pod missed the 90-second readiness window.
Usual causes are a slow first image pull, volume attach delays, exhausted quota, or a missing RuntimeClass when workspace.runtimeClassName is set.In a chat, only the workspace tool call that waited fails with this message; the response itself continues. The control-plane or executor log records a workspace.start.failed event with the chat and run IDs.
workspace.imagePullSecret is not set. The control plane’s imagePullSecrets does not apply to workspace pods, so both must be configured for private images.
Either activity is genuinely ongoing, a lease is stuck above zero from a process that never finished, or the reconciler is erroring. Check control-plane logs and confirm WORKSPACE_IDLE_SECONDS.
The container hit its memory limit and was OOM-killed:
Raise workspace.resources.limits.memory.
Only /home/r5d persists. Anything installed into system paths is lost when the pod scales to zero. Add durable tooling to the workspace image instead.
Recoll indexes incrementally and may not have indexed recent files yet. Very new or unsupported formats also return no matches. Try grep for exact text.

Models and providers

The outbound guard blocked the URL. It must be HTTPS and publicly resolvable, unless ALLOW_PRIVATE_EGRESS or ALLOW_INSECURE_HTTP is enabled.
The stored API key is invalid or lacks model access. Keys are write-only; re-enter rather than trying to read it back.
The provider model ID must match the provider’s exact identifier, and the base URL should end at /v1 without repeating the version segment.
Edit the model and turn off Image input for text-only models. It defaults to on; OpenAI-compatible endpoints do not all support images. With it off, readfile uses OCR text and other tool images are replaced with an omission note, including images in older conversation history.If an image-containing request is rejected with HTTP 400 or 422 before the provider starts streaming, chat retries that model request once without images. Tools are not repeated. A notice names the model and this setting; operators can find the provider.image_input.rejected warning in server logs. Remaining requests in that run omit images too. The transcript and model configuration are not changed: a bad image can also cause a rejection, so later turns try image input again and have the same fallback. If the text-only attempt also fails, check the provider and the model’s Image input setting.Images omitted during fallback are not interpreted or automatically OCR’d. Turn off Image input and ask the agent to read the file again for OCR, or choose a vision-capable model. Endpoints that silently ignore images cannot be detected this way. Partial streams, network failures and authentication errors are never retried by this fallback.
The configured context window exceeds the model’s real limit. Lower it to the documented value.
The provider answered successfully but sent no text, reasoning or tool calls. The response is recorded as failed, not completed, and nothing ran. Nothing is retried automatically: Resume response asks the model again. The notice shows the run and response IDs, which match the chat.response.timing record with outcome empty_response, so the request can be traced in provider or proxy logs. A response a content filter stopped, or that reached its output limit before writing anything, is named as such instead.
SETTINGS_ENCRYPTION_KEY no longer matches the one used to encrypt the data, usually after a restore. Restore the original key; otherwise credentials must be re-entered.
The application promotes the oldest enabled model automatically when a default is removed. If no enabled model exists, add or enable one.

MCP Apps

If ordinary MCP tools work but the interactive interface is unavailable, check mcpApps.sandboxOrigin (MCP_APPS_SANDBOX_ORIGIN) and the separate sandbox Deployment. A healthy product /api/health does not verify sandbox routing. The chart creates no sandbox Ingress: wildcard DNS and TLS must route to the sandbox Service on port 3002, not the product Service. See MCP Apps for origin validation errors, browser checks, proxy configuration, and rollback without disabling ordinary MCP tools.

Helm

GitHub Pages must be enabled for the repository and at least one release must have published an index.yaml. Verify directly:
The local cache is stale. Run helm repo update r5d-chat, then helm search repo r5d-chat --versions.
The package is private. Authenticate with a token that has read:packages:
With --atomic, Helm reverts automatically. Inspect why before retrying:

Slow responses

Each chat response logs one chat.response.timing JSON line: the control plane logs it for direct responses, and the executor for durable runs. Each stream a browser follows for a durable run logs one chat.stream.delivery line in the control plane. Records carry chat, run, message, and request IDs, never prompts, output, tool payloads, or credentials.
The phases in chat.response.timing are consecutive, so the largest one shows where the time went. After queueMs, they add up to firstVisibleMs: the time from the start of execution until the first model output was visible. firstByteMs counts any upstream activity after the request was sent, including keep-alives, so a small firstByteMs with a large firstContentMs means the provider was connected but not yet generating. workspace describes the background workspace start: its state, how long it took (startMs), and how long tool calls waited for it (toolWaits, toolWaitMs). chat.stream.delivery describes what one browser received: when the first model content was sent (firstContentMs), how long after it was saved (contentLagMs), and how many keep-alive comments the server sent to hold the connection open (keepalives). Keep-alives never count as output.

Collecting diagnostics

When reporting an issue, gather non-sensitive context:
Review the output before sharing it. helm get values can include credentials if you passed them through values instead of existingSecret.