Troubleshooting & qualification
Diagnose installation, sign-in, launch, FHIR access, and credential failures without exposing private data.
Begin with the software revision, integration pathway, installation, and failing stage. A discovered FHIR endpoint, an enabled registration, a completed authorization exchange, and a successful resource read are separate observations. Keep the request ID and sanitized error code so a report identifies which stage failed.
Installation does not start
- Confirm the local Docker daemon is running and Compose v2 is available. Docker Desktop must use Linux containers. Remote Docker daemons are outside the guided installation workflow.
- Check the selected ports. The installer does not stop unrelated services. Choose unused ports for a new installation rather than changing a saved installation’s registered origins.
- Run the installer from the source directory and choose a separate, private installation directory. Do not run two installer processes against one directory.
- For a source build, allow downloads of the pinned base images and dependencies. A runtime image archive by itself is not an air-gapped installation bundle.
Use bash ./install.sh --help or .\install.ps1 --help for supported arguments. Follow the installation guide for saved configuration, image verification, and status/start/stop controls.
The console opens, but API requests fail
Check the run mode and origin. Source development uses console port 3010 and API port 3001. The Docker sandbox combines console/API at 3010. The repository production Compose stack publishes its combined service at loopback 3001 by default. Use the URLs generated for your actual installation.
Use 127.0.0.1 consistently for the default local environment. An origin using localhost, a different port, HTTP instead of HTTPS, or a different path is not an exact match for a registered callback. Explicit IPv4 loopback also avoids reaching another application’s IPv6 listener through localhost.
Administrative sign-in fails
For local accounts, check ADMIN_AUTH_MODE=local, the normalized username, enabled state, and the password policy. There is no public forgotten-password email flow. A trusted operator can perform the offline recovery procedure in administration.
For OIDC, confirm the exact issuer, callback URL, client authentication method, and approved endpoint origins. Access not granted after a successful provider login usually requires checking the provisioned exact issuer/subject pair and enabled state. Email and group claims do not create accounts or grant roles. OIDC mode never falls back to local password authentication after a provider outage.
If configuration is visible but an action is denied, check both organization and application assignments. Viewer access intentionally denies writes and operational actions. Once a first enabled owner exists, resetting bootstrap flags does not bypass that stored owner.
An EHR launch fails
Review Recent activity and launch details:
| Recorded stage | What it establishes |
|---|---|
launch.rejected |
Rejection occurred before app bootstrap, such as issuer/launch-handle validation |
launch.authorizing |
Browser was directed to the configured EHR authorization endpoint |
launch.denied |
A bound OAuth callback returned an authorization denial |
launch.failed |
Token exchange or activation requirements failed |
activation.ready |
OAuth and required launch context completed; subsequent FHIR access is a separate check |
Use the worksheet’s exact launch URL and OAuth callback. The incoming EHR iss must match the installation’s full configured FHIR base, including its path. Create a fresh launch through the vendor launcher instead of reusing a copied URL, launch handle, or authorization code.
A sanitized invalid_grant or invalid_launch_token does not identify one universal cause. Compare the intended patient or clinician audience, selected registration, exact callback, requested scopes, and current vendor/customer enablement. Do not infer that a patient account is broken from the error alone. Older generic denial events cannot retrospectively recover discarded upstream codes.
A registration requires HTTPS
For source development with a sandbox that rejects HTTP callback URLs:
npm run https:setup
# Complete the explicit certificate-trust step reported by setup.
# Stop an existing dev stack first.
npm run dev:https
This provides the loopback bridge endpoint https://127.0.0.1:3443. It does not create a public tunnel or install certificate trust automatically. Use the worksheet’s exact connection callback. Do not disable certificate verification to bypass a trust failure.
See local HTTPS development for the trust boundary and sandbox qualification details.
Authorization succeeds, but a FHIR request fails
Check that the selected connection has the required resource interaction, granted scopes, and patient permissions. The current gateway supports metadata and JSON read/search interactions; writes, arbitrary operations, and bulk export are outside its current scope.
For direct access, confirm installation token-export policy and upstream browser CORS. Call the lazy credential provider on each request that needs authorization; a saved token can expire while the activation remains active. Gateway and direct credentials authorize different endpoints: do not send a local gateway session token to the EHR as if it were an upstream token.
For pagination, follow only the controlled links for the selected base and activation. Do not attach credentials to arbitrary returned URLs or redirects. Missing or inaccessible observations must remain missing records, not healthy values.
Refresh or handoff fails
Confirm a single renewal owner and an installation that permits the requested access mode. During bridge-managed renewal, original-token responses withhold refresh tokens intentionally. An explicit supported handoff transfers ownership once; replaying it is not a renewal mechanism.
A confidential upstream registration can require client authentication even after handoff. The private key or client secret is not exported. Native/public apps need a trusted backend for that confidential authentication. Sender-constrained grants are rejected by this release unless supported through a compatible future proof adapter.
Readiness or recovery fails
GET /health being available does not prove the database and key work; use GET /ready. Confirm the intended database, its availability, and the exact encryption key for its records. Do not generate a replacement key to open an existing encrypted database.
A verified backup still needs a restore rehearsal into a separate empty database. Stop every service replica before the documented offline maintenance operations. Consult operations for restore and rotation requirements.
Report a reproducible issue
Open a GitHub issue with the version/commit, platform, run mode, synthetic reproduction steps, pathway, generated request ID, and fixed error code. Use fictional data and sanitized configuration. Exclude patient records, authorization URLs with parameters, token responses, cookies, keys, passwords, private installation plans, and database files.
Real vendor/pathway qualification requires its own registration and end-to-end evidence. The project currently includes synthetic protocol tests, SDK checks, browser flows, and operational validation; those checks establish their tested behavior rather than universal EHR compatibility.
Source references: development diagnostics, administration, security, and release boundaries.
Questions or improvements? Open an issue on GitHub ↗. Guides reflect the v0.1 source foundation; check your checkout’s runbooks when upgrading.