Troubleshooting

This guide covers common problems and verified troubleshooting steps for the current Adapt implementation.

Server Startup Problems

Port Already in Use

netstat -ano | findstr :8000
adapt serve . --port 8001

Invalid Configuration

adapt check .

Look at .adapt/conf.json for invalid keys or JSON syntax errors.

TLS Startup Error

If one TLS flag is provided without the other, startup fails.

Use both together:

adapt serve . --tls-cert /path/to/cert.pem --tls-key /path/to/key.pem

Authentication Problems

Login Fails

  • Make sure that the username exists
  • Make sure that the password is correct
  • Make sure that the user is active

Useful checks:

adapt admin list-users .
sqlite3 .adapt/adapt.db "SELECT username, is_active FROM users;"

If the user is inactive, activate the user:

adapt admin activate-user . --username <username>

API Key Returns 401

  • Make sure that the header has this format: X-API-Key: <key>
  • Make sure that the key is active and not expired
  • Make sure that the key owner is active
curl -H "X-API-Key: your-key" http://localhost:8000/auth/me

Authorization Problems (403)

  • Make sure that the group membership is correct
  • Make sure that the resource permission names are correct
  • Make sure that you use the correct action, read or write

Useful checks:

adapt admin list-groups .
adapt admin list-resources .

Generated API, schema, and UI routes require authentication plus the corresponding resource permission. create-permissions creates individual groups named <resource>_readonly and <resource>_readwrite. Combined group names include a suffix made from all selected resources.

When an unsafe request uses the adapt_session cookie, it must also send the adapt_csrf cookie value in the X-CSRF-Token header. This rule remains true if the request also includes an API key. For command-line mutations, use an API key without a session cookie to avoid CSRF handling.

Resource Discovery Problems

Files Not Appearing

  • Make sure that the plugin registry contains the file extension.
  • Make sure that the selected plugin detects the file.
  • Make sure that the file is under docroot.
  • Restart the server after you add files.

Supported built-in extensions are:

  • Datasets: .csv, .xlsx, .xls, .parquet
  • Rendered content: .html, .md
  • Python handlers: .py
  • Generic text and document files served by FilePlugin: .txt, .pdf, .json, .xml, .svg
  • Generic image files served by FilePlugin: .png, .jpg, .jpeg, .gif, .webp
  • Streamed media: .mp4, .mp3, .avi, .mkv, .webm, .ogg, .wav

Adapt discovers and reads legacy .xls files. These resources are read-only. Convert a legacy workbook to .xlsx before you modify it through Adapt. Unregistered extensions need a plugin mapping before Adapt can discover them. See Known Limitations.

Companion Files Missing

Run discovery check:

adapt check .

Companion files are generated under .adapt/ for supported resource types.

Dataset Write Problems

405 Method Not Allowed

The server can be in read-only mode. A legacy .xls resource is also read-only.

adapt serve . --readonly

409 Conflict

When another operation holds the resource lock, Adapt returns 409. Adapt also returns this response when it exhausts all lock acquisition retries.

Inspect /admin/locks and the server log. Then retry the write after the competing operation finishes.

Write Payload Rejected

Dataset mutations require action envelope payloads on /api/<resource>/.

Example:

{"action":"update","data":{"_row_id":1,"name":"Updated"}}

Admin API Troubleshooting

Use implemented admin routes under /admin, for example:

  • /admin/users
  • /admin/groups
  • /admin/permissions
  • /admin/locks
  • /admin/cache
  • /admin/api-keys
  • /admin/audit-logs

Plugin Troubleshooting

Custom Plugin Not Loading

Make sure that the class path format in plugin_registry is correct:

{
  "plugin_registry": {
    ".ext": "module.path.ClassName"
  }
}

Current loader expects dotted class paths, not module:path syntax.

Make sure that the custom plugin detect(path) method returns True for the file. When detection rejects the file, Adapt does not call load(path).

Import Errors

Do a manual test of the import:

python -c "from module.path import ClassName"

Useful Diagnostic Commands

adapt check .
adapt list-endpoints .
adapt admin list-resources .
adapt reindex .

adapt check initializes storage and reports a discovered-resource count. It also reports TLS file problems and top-level route collisions. It does not migrate resource schemas or list each resource.

adapt list-endpoints builds the configured plugin routers and prints their mounted resource paths. It includes sub-resources such as Excel sheets. It does not invent API, schema, or UI paths for files that mount no routes.

adapt reindex rebuilds the full-text search index. Add --force to index resources whose file metadata is unchanged.

When to Collect Logs

When you report an issue, capture these logs:

  • startup failure output
  • traceback for 500 errors
  • request path and response code
  • relevant configuration from .adapt/conf.json

Deployment Troubleshooting (Container and Kubernetes)

See Deployment for the full container and Helm chart documentation. This section covers the failures those paths hit most often.

Pod CrashLoopBackOff with ADAPT_PORT must be an integer

Older chart versions injected Kubernetes service-link variables. A Helm release named adapt then set ADAPT_PORT to a URL, and the server rejected it. Chart 0.5.2 sets enableServiceLinks: false on the server and bootstrap pods. Upgrade to chart 0.5.2 or later if you still see this error. See Kubernetes (Helm) → Install.

Pod CrashLoopBackOff on a PVC the container cannot write

The container runs as UID 1000. If the mounted PVC is owned root:root (common with drivers that ignore fsGroup), Adapt cannot create .adapt/ and the pod crash-loops. The chart sets podSecurityContext.fsGroup: 1000 by default, which most CSI drivers honor; for the drivers that ignore it, use persistence.annotations (driver-specific) or pre-chown an existingClaim to UID/GID 1000 before mounting it.

docker run bind mount: Permission denied: '/data/.adapt'

Same root cause as above, on a plain Docker/Podman bind mount instead of a PVC. Fix it on the host:

sudo chown 1000:1000 ./docroot

See Container.

Liveness restarts during startup indexing

A large document root with search_on_startup enabled can take longer to index than the default liveness window, causing Kubernetes to restart the pod before it finishes starting. The chart's probes.startup block exists for this — increase probes.startup.failureThreshold (default allows about 5 minutes) if your document root is large enough to need more.

Copied files return 404 immediately after kubectl cp

Adapt discovers resources once, at process startup — not continuously. A file copied into a running pod is not reachable until the pod restarts:

kubectl rollout restart deployment/<release>-adapt

See Kubernetes (Helm) → Getting documents into the document root.

bootstrapAdmin.enabled=true rejected without persistence

This is intentional: charts/adapt/templates/admin-bootstrap-job.yaml fails the render with fail() rather than silently bootstrapping a user into a throwaway emptyDir the main pod cannot see. Set persistence.enabled=true alongside bootstrapAdmin.enabled=true.

Failed bootstrap Job blocks reinstall

Helm retains a failed hook Job for diagnosis instead of cleaning it up automatically. A retained failed Job (and its pod holding an RWO volume) can block a reinstall or leave the PVC Terminating. Delete it first (substitute your own release name for myadapt):

kubectl delete job myadapt-bootstrap-admin
kubectl get pods -l job-name=myadapt-bootstrap-admin

If a pod from that Job is still present, delete it too, to release the volume — substitute the pod name printed by the command above:

kubectl delete pod myadapt-bootstrap-admin-abc12

Bootstrap or server Job stuck ContainerCreating

An RWO volume is bound to whichever node its first mounting pod was scheduled on. If the bootstrap Job or a rescheduled server pod lands on a different node, it stays ContainerCreating waiting for the volume to detach and reattach. This is a real multi-node constraint independent of replica count — see the RWX/multi-replica guidance in Kubernetes (Helm) → Admin prerequisites.

Empty landing page after a default install

Installing with defaults (persistence.enabled=false, bootstrapAdmin.enabled=false) gives you an empty, account-less, ephemeral instance — there are no documents, no users, and any state is lost on the next pod restart. helm get notes <release> says so explicitly. This is expected; follow the day-1 walkthrough for a populated, logged-in instance.

Manual navigation: Previous: Architecture | Index | Next: Known Limitations