Skip to content

Troubleshooting

Most Docsentry failures are deliberate. The system prefers refusing to start, or refusing to serve, over continuing in a state where the damage would surface later and be harder to attribute. That makes the messages below diagnostic rather than mysterious - each one names the condition it detected.

Work down from the section that matches when the failure happens.

Startup validation runs before the host binds a port. If any of these fire, nothing is served at all - which is the point.

DataProtection:KeyPath must be set outside Development

Section titled “DataProtection:KeyPath must be set outside Development”

The Data Protection key ring encrypts authentication cookies, the antivirus API key, the other protected settings, and the keys that unwrap every stored document. Outside Development, Docsentry refuses to invent a location for it, because the default location is inside the content root - where a deployment would silently recreate it on every release and sign every user out.

Set DataProtection:KeyPath to an absolute path on durable storage, outside the content root, and back it up. A relative path is rejected with the same class of error.

See Security hardening.

The runtime database principal is over-privileged

Section titled “The runtime database principal is over-privileged”

Docsentry checks at startup that the identity in ConnectionStrings:DefaultConnection is a member of DocsentryAppRole and not a member of db_owner. The message names which of the two conditions failed.

This is the two-principal model: the identity that deploys schema and the identity that runs the application are deliberately different, so a compromised application cannot rewrite its own audit log. Point the connection string at the least-privilege login, not at the account used for deployment.

See Database deployment.

The storage key material cannot be unwrapped

Section titled “The storage key material cannot be unwrapped”

At startup Docsentry unwraps its storage key material with the Data Protection key ring and checks its fingerprint. If the key ring is missing, is a different ring, or was DPAPI-protected on another machine, the application refuses to start rather than serving documents it cannot decrypt.

Restore the key ring that belongs to this database. There is no way to recover encrypted content without it. See Backup and restore.

Security settings such as AccountSecurity:SecurityStampValidationMinutes, AccountSecurity:InvitationLifetime, RateLimiting:CredentialVerificationPermitLimit, ContentIsolation origins and PublicSite:BaseUrl are validated at startup. An invalid value stops the host with a message naming the setting, rather than being silently clamped.

The host exits when Workflows:Engine is Elsa

Section titled “The host exits when Workflows:Engine is Elsa”

The Elsa engine needs its own deploy script applied. If it has not been, the application refuses to start rather than starting successfully and failing at the first workflow - long after anyone would connect the two events.

Either apply the script, or set Workflows:Engine back to Dapper, which is the default and needs nothing beyond the standard schema.

A deploy script fails with a checksum mismatch

Section titled “A deploy script fails with a checksum mismatch”

Every applied script’s SHA-256 is recorded in dbo.DmsSchemaVersions and re-validated on replay. A mismatch means a script that was already applied has been edited since.

Do not “fix” the ledger. Restore the script to the bytes that were applied, and ship the correction as a new numbered script - the deployment sequence is forward-only by design.

The Data Protection key ring was not preserved. Cookies issued by the previous instance cannot be decrypted by the new one, so every session is invalid.

Confirm DataProtection:KeyPath points outside the content root and survives the release, and that the key ring is included in your backups. It is a credential: restoring a database without it does not restore working sessions.

Symptom Cause What to do
Correct password rejected, account unusable Lockout after repeated failures Wait out the lockout window, or clear it as an administrator.
An administrator can only reach the two-factor enrolment page Two-factor is mandatory for their role Enrol an authenticator app. Sign-out stays available.
An invitation link is refused It expired, or a newer invitation was sent Resend the invitation from the Users list.
A new password is refused as breached It appears in the configured breached-password corpus Choose a different password.
A revoked user is still signed in Sessions revalidate on an interval Wait up to AccountSecurity:SecurityStampValidationMinutes (2 by default).
429 Too Many Requests at the sign-in form Rate limiting, metered per account and per IP Wait for the interval named in Retry-After.
Sign-in works locally, fails behind a proxy Forwarded headers not configured, so the app sees the proxy’s IP Configure the known proxies and networks; the fail-closed default is to ignore untrusted headers.

The per-account and per-IP buckets are chained deliberately: metering on IP alone locks out a whole office when one person forgets their password. See Security hardening.

The upload allowlist checks three things and requires all three to agree: the file extension, the declared MIME type, and the content sniffed from the first bytes. A .pdf that is really a ZIP fails, and so does a genuine PDF sent with the wrong content type.

Check Upload allowlist for the permitted set, and the folder’s own upload policy, which can narrow the global list further but never widen it.

Size limits apply per content type and can be set per folder. The effective limit for a folder is resolvable at /api/v1/folders/{id}/effective-upload-policy - use that rather than guessing which layer refused.

An upload stops partway and cannot be resumed

Section titled “An upload stops partway and cannot be resumed”

Upload sessions are resumable, but abandoned ones are swept by a background job. Once swept, the session id is gone and the upload must start again. See Uploading.

Download is refused on a document that clearly exists

Section titled “Download is refused on a document that clearly exists”

The version has not cleared antivirus scanning. Docsentry is fail-closed: unscanned content is never served, because the alternative is serving malware during the window before a scan completes.

Check the scan status on the document. If it is stuck rather than failed, confirm the antivirus-backfill job is enabled and running - it picks up any file whose scan never ran. With VirusTotal, a large backlog drains slowly because lookups are rate-limited. See Antivirus. If the file genuinely failed a scan, it is in quarantine and is not going to be served.

An unavailable preview means generation has not happened yet or failed. A preview that exists but cannot be read is discarded and regenerated automatically.

Document kind Needs If missing
Office formats LibreOffice on the host The preview is unavailable; the original still downloads.
PDF and images Built-in rendering Check the preview generation job.

LibreOffice is discovered automatically at the usual install locations. If it is installed somewhere unusual, configure the path explicitly. See Previews.

Deleting documents does not free disk space

Section titled “Deleting documents does not free disk space”

This is correct behaviour, not a fault. Two mechanisms are in play:

  1. Soft delete moves an item to the recycle bin. Nothing is removed until retention purges it.
  2. Deduplicated storage keeps identical content once and references it from every document with that content. Removing one document does not remove the stored file while another still points at it.

See Governance and retention.

Docsentry probes for a full-text index at startup and caches the answer for five minutes. If no index is available it falls back to a LIKE predicate. That is correct but not sargable - it scans rather than seeks, and the cost grows with the corpus.

On a large repository the difference is roughly an order of magnitude. Install and populate full-text search on the SQL Server instance to remove it.

Two likely reasons, in order:

  1. Permission trimming. Results are trimmed rather than marked forbidden. A document you cannot read does not appear at all - it is not hidden with a message. Check effective permissions on it.
  2. Text not yet extracted. Content search matches extracted text. A document whose OCR has not run yet matches on metadata only.

The status field distinguishes the two failure modes, and they need different fixes:

Status Meaning
Pending The job never ran. Background processing is not running, or is backed up.
Failed The job ran and the OCR engine could not be reached or could not process the file.

Pending points at Background jobs. Failed points at the Tesseract installation and its language data - Docsentry uses eng+ara, and a missing Arabic data file fails the whole extraction, not just the Arabic part.

Notifications are written to a durable outbox and sent by a background job, so a message that has not arrived is either not yet drained or failing to send.

  1. Open the email settings screen. It shows whether mail is actually deliverable: the server switch, host and sender, and the administrator switch must all be on. Until they are, mail is held, not failed.
  2. Send a test message. It sends immediately, bypassing the outbox, so it isolates SMTP problems.
  3. Check the recipient’s own notification email preferences - a user can turn categories off.
  4. Mail that waited longer than the holding window (3 days) before email was configured is suppressed rather than sent late.

If notification emails arrive without links, set PublicSite:BaseUrl.

See Email.

Audit integrity reports Broken or Unverifiable

Section titled “Audit integrity reports Broken or Unverifiable”

Broken means an audit row or seal no longer matches what was sealed - a row changed, was removed or was inserted outside the application. Treat it as a security incident: the findings name the seal and row, and the off-box copy of the seal log events shows what the chain looked like when it was sealed.

Unverifiable means the evidence to check part of the chain is gone, most often because the key ring that signed those seals was replaced or lost. It is not proof of tampering, but it is a loss of evidence worth recording.

Rows cleared by privacy retention or erasure are reported as lawfully redacted, not as Broken.

Symptom Likely cause
A definition cannot be started on a document The definition is Draft or Archived; only Active definitions start.
A task or signature slot is in nobody’s inbox Its assignee can no longer act on it. Reconciliation reassigns these, but only when it runs.
A step is marked Escalated It was outstanding beyond the configured window. That is the mechanism working.
A folder’s documents are not entering approval The folder has no approver workflow bound. Manual starts depend on someone remembering.

docsentry-backup restore repairs orphaned database users, relocates database files and clears scheduled job state for you. If you restored by hand instead, check those three things yourself:

  • Orphaned database users. Restoring onto a different server carries the users but not their server-level logins. Re-map each user (ALTER USER ... WITH LOGIN = ...), then confirm the runtime principal is still a DocsentryAppRole member and still not db_owner.
  • The key ring. Without the matching key ring the application refuses to start, because it cannot unwrap the storage key material.
  • The storage tree. The database alone is not a working system.

See Backup and restore.

Docsentry logs structured events. When something is wrong, the useful ones are:

  • Startup validation - every refusal above is logged before it is thrown.
  • Background job execution - a job that is not appearing is not running.
  • Rate limiting and shedding - 429 and 503 responses are logged with the bucket that produced them.

A health probe is available at /api/v1/health. It is anonymous and exempt from rate limiting, so it stays answerable when the rest of the application is shedding load.