Troubleshooting
“Narratorr isn’t connected yet” on search
Section titled ““Narratorr isn’t connected yet” on search”Search and requests need the narratorr connection. An admin must set narratorr’s Server
URL (full base URL including scheme, e.g. http://narratorr:3000) and API key on the
Settings page and Save (use
Test first to verify). Until then, search returns this notice.
Container crash-loops with SQLITE_CANTOPEN
Section titled “Container crash-loops with SQLITE_CANTOPEN”The log shows a libSQL open failure — Unable to open ... database file, SQLite code 14
(SQLITE_CANTOPEN) — and the container exits and restarts in a loop (migrations run before the
server listens, so a database it can’t open is a hard boot failure). The container runs as the
non-root node user (uid 1000) and can’t write its data directory.
This happens with a host bind mount whose directory is owned by root. Fix the owner on the host and restart:
sudo chown -R 1000:1000 /path/on/host/narratorr-requestsdocker restart narratorr-requestsA named volume avoids this entirely — see Installation.
App refuses to start in production
Section titled “App refuses to start in production”The app fails fast at boot (rather than come up insecure) if:
SESSION_SECRETis unset (production only) — set it (openssl rand -hex 32).AUTH_BYPASSis enabled (production only) — it’s refused entirely there; setAUTH_BYPASS=0.- No auth method is enabled (any environment) — enable
LOCAL_AUTHand/or configure an OIDC provider. - The environment is malformed — an incomplete
OIDC_<ID>_*block, an invalid or duplicate provider id, an unreadable*_FILEsecret, a badBOOTSTRAP_ADMIN— the startup error names the variable.
Blank page (or can’t log in) over plain HTTP
Section titled “Blank page (or can’t log in) over plain HTTP”The app renders a blank page, or the page loads but sign-in silently fails, on a production
deploy with no TLS in front (no reverse proxy terminating HTTPS). This happens because
BEHIND_TLS defaults to NODE_ENV=production’s value — so a plain-HTTP prod deploy inherits the
CSP upgrade-insecure-requests directive (the browser tries to upgrade asset requests to HTTPS,
which don’t exist, and blocks them) and a Secure session cookie (which a plain-HTTP browser won’t
send back).
Fix: set BEHIND_TLS=false if you’re genuinely running production over plain HTTP with nothing
terminating TLS in front. Leave it unset (or true) once a reverse proxy / load balancer does
terminate TLS — see Installation.
Blank page (or can’t log in) over plain HTTP
Section titled “Blank page (or can’t log in) over plain HTTP”The app renders a blank page, or the page loads but sign-in silently fails, on a production
deploy with no TLS in front (no reverse proxy terminating HTTPS). This happens because
BEHIND_TLS defaults to NODE_ENV=production’s value — so a plain-HTTP prod deploy inherits the
CSP upgrade-insecure-requests directive (the browser tries to upgrade asset requests to HTTPS,
which don’t exist, and blocks them) and a Secure session cookie (which a plain-HTTP browser won’t
send back).
Fix: set BEHIND_TLS=false if you’re genuinely running production over plain HTTP with nothing
terminating TLS in front. Leave it unset (or true) once a reverse proxy / load balancer does
terminate TLS — see Installation.
AUTH_BYPASS won’t bind a non-loopback host
Section titled “AUTH_BYPASS won’t bind a non-loopback host”By design — an AUTH_BYPASS instance has no auth, so it refuses to listen on anything but
loopback. If you really mean to (an isolated host), set ALLOW_INSECURE_AUTH_BYPASS=1. Better:
turn AUTH_BYPASS off and configure a real auth method.
A new user is stuck on “Awaiting approval”
Section titled “A new user is stuck on “Awaiting approval””That’s the approval queue working as intended. An admin approves them on the Users page
(→ active). The very first user becomes admin automatically; if no one is admin yet, see
BOOTSTRAP_ADMIN in Authentication.
OIDC sign-in fails (“Sign-in failed. Please try again.”)
Section titled “OIDC sign-in fails (“Sign-in failed. Please try again.”)”The provider callback didn’t complete. Check that:
OIDC_<ID>_REDIRECT_URIis set and byte-identical to the URI registered at the provider (https://<your-public-url>/api/auth/oidc/<id>/callback) — the app sends that configured value to the IdP and rebuilds the callback from it, never from the incomingHostheader. A trailing slash orhttp:vshttps:mismatch fails the exchange.OIDC_<ID>_ISSUER,OIDC_<ID>_CLIENT_ID, and the client secret (if the provider requires one) are correct.- Your reverse proxy actually forwards
/api/auth/oidc/<id>/callbackthrough to the app.
A request is stuck on “Processing”
Section titled “A request is stuck on “Processing””Processing (acquiring) means narratorr is still working — searching, downloading, or
importing. The timing is narratorr’s, not narratorr-requests’s: a request stays in Processing
for as long as narratorr hasn’t imported the book yet (it may legitimately sit “wanted” until
narratorr’s next scheduled search). Check the book’s state in narratorr. If it ultimately fails,
the request flips to Failed with a reason.
No “Get eBook” button anywhere
Section titled “No “Get eBook” button anywhere”eBook affordances appear only when all of these hold:
- Enable ebook support is on in Settings → eBooks.
- The connected narratorr also has eBook support enabled — narratorr-requests probes narratorr’s capability and hides everything eBook when it’s off (or the narratorr version predates it). The probe is cached, so give it a couple of minutes after flipping the narratorr side.
- The book is In library (imported). A book still on the way shows no eBook action until narratorr finishes importing it.
- narratorr actually has a companion EPUB paired with the book — an imported book without one shows a No eBook pill instead of the button.
Send to Kindle is disabled in the sheet
Section titled “Send to Kindle is disabled in the sheet”Two different gates, told apart by the copy under the button:
- “Send to Kindle isn’t available on this instance right now.” — instance-side: there’s no confirmed Kindle sender. An admin selects an Email (SMTP) notifier under Settings → eBooks. If it was working before, the selected notifier’s From address probably changed — that section shows an alert, and delivery stays paused until you Reconfirm sender. (The same copy also shows for a moment while the feature check is still loading — reopen the sheet before chasing config.)
- “Send to Kindle needs your device address” — user-side: add your
@kindle.comaddress in the account modal (click your username → Kindle address).
”Sent to Amazon” but nothing arrives on the Kindle
Section titled “”Sent to Amazon” but nothing arrives on the Kindle”Delivery past that point is Amazon’s side of the handoff:
- The approved-sender list is the usual culprit — Amazon silently drops personal documents from unapproved senders. Approve the app’s sender address (shown in the account modal and on the send sheet) on your Approved Personal Document E-mail List — not your own Kindle address. One-time per Amazon account; steps in Setting up Send to Kindle.
- Conversion and delivery take a few minutes — check the Kindle library or Amazon’s Content & Devices for the document before re-sending.
- Books over Amazon’s 25 MiB personal-document cap are refused up front with a “download it instead” message — nothing is sent, so nothing will arrive.
Notifications aren’t arriving
Section titled “Notifications aren’t arriving”- Confirm the notifier exists and its Test passes on the Settings page.
- Set the Public URL if you want deep-links back to the app in notifications (the queue or the Users page, depending on the event).
- Admin events (New request, New signup, Request failed) fire only over notifiers that have that event checked — each notifier picks its own in its Events field. A notifier with no events selected even hides its Test button.
- Requester emails (approved / denied / ready-to-listen) need three things: an Email (SMTP) notifier configured, a contact email on the requester’s account, and the matching opt-in checked in their account modal (click your username). Without an SMTP notifier the opt-ins render disabled with an explanation. Requesters can always track status on their My Requests page (which updates live).
Checking health
Section titled “Checking health”GET /api/health reports readiness — it pings the database and reports whether narratorr is
configured. The Docker image ships a matching HEALTHCHECK, so docker ps / your orchestrator
will show the container as healthy/unhealthy.