No reports are arriving
Work down the chain — most often it’s the first item.
- Has it been 24 hours? Reports are sent once a day per receiving provider. Nothing arrives within minutes of publishing a record.
- Is the DMARC record live? Check it resolves and contains a
rua=:
The Domain detail page’s record inspection shows the same thing, parsed.dig +short TXT _dmarc.yourdomain.com - Does
rua=point at the mailbox you connected? A typo here fails silently — receivers just send reports somewhere else. - Is the mailbox syncing? Check Mailbox sources for the latest run status, and trigger a manual sync rather than waiting an hour.
- Is anyone actually sending mail from the domain? A parked domain with no traffic legitimately produces no reports.
Mailbox authentication fails
Nearly always credentials rather than configuration:
- Use an app password, not the account password — see connecting a mailbox.
- Confirm IMAP is enabled for the account. Many Microsoft 365 tenants disable IMAP basic auth entirely; if so, that mailbox can’t be used yet.
- Verify host and port (usually
993with TLS). - If you added
Security__CredentialEncryptionKeyafter saving a mailbox, its password is re-encrypted on the next sync — re-save the mailbox if the key changed.
The worker isn’t ingesting anything
Check it’s running and what it’s saying. On the default single-container install
the polling loop lives in the app container; if you split them, use worker.
docker compose ps
docker compose logs --tail=50 app
Exited— most likely it started against a database with no schema. On a split stack the worker waits for the console to report healthy; if you wrote your own compose file, reproduce that ordering.- Running but idle — with default settings it polls every 60 minutes. Confirm at least one mailbox source is active, and that its protocol is IMAP.
- Repeated
Worker scheduler pass failed— the message includes the underlying error; a database connection problem is the usual cause.
”Another worker already holds the ingestion lock”
The container exits on startup with that message. It is doing the right thing: only one worker may run against a database. Two ingestion loops duplicate every sync pass and can send duplicate alert and digest email, so the application takes a Postgres advisory lock and a second worker refuses to start.
Usual causes:
- A
workercontainer alongside anAPP_MODE=allone. The combined container already runs the loop. Either drop the separate worker, or switch the app toAPP_MODE=api— thecompose.split.ymloverlay does both at once, which is why using it is safer than editing by hand. docker compose up --scale worker=2. Not supported. Scale the console instead (APP_MODE=apireplicas take no lock).- A worker that was killed abruptly. If the previous container was
SIGKILLed or the host lost power, Postgres still holds its lock until it notices the dead connection — usually a minute or two. The replacement will crash-loop until then and then start normally. Wait rather than intervening.
You can confirm who holds it:
docker compose exec -T postgres psql -U postgres -d dmarc_analyzer -tAc \
"select count(*) from pg_locks where locktype = 'advisory'"
Kubernetes: pods restart a few times on first install
Expected on a fresh install if you are not using the published chart. Every pod in
a release starts at once — Kubernetes has no equivalent of Compose’s
depends_on: condition: service_healthy — so the app can come up before PostgreSQL
is accepting connections, fail with Name or service not known, and be restarted
until the database is ready. It converges, but the restart backoff can turn a
20-second wait into minutes.
The chart handles this with a wait-for-database init container. If you wrote your
own manifests, add one.
Parse failures in the sync history
A run reporting parseFailures above zero means an attachment couldn’t be read.
Common causes:
- An unusual ZIP compression variant.
- Something in the mailbox that isn’t a DMARC report — many providers also send
TLS-RPT reports, and marketing mail lands in shared
inboxes. If TLS reports are a steady share of the failures, point their
rua=at a different mailbox so this count stays meaningful.
The rest of the run still imports; failures are counted, not fatal. If a mailbox shows persistent failures, it’s worth opening an issue with the attachment name.
The dashboard looks empty but reports imported
Analytics windows anchor to your newest report, not today. If you imported only historical data, “last 30 days” covers the 30 days before that newest report — so data exists but the default window may sit past it. Widen the window with the day selector.
The login form accepts my password and returns me to the login page
No error, no failed-login entry that helps, just a loop.
On 0.2.1 and earlier this was a bug, and upgrading fixes it. The session cookie
was always marked Secure, and browsers accept a Secure cookie over http://
only on localhost — so sign-in worked at http://localhost:8080 and silently
failed at http://dmarc.internal:8080 or http://10.0.5.7:8080. The server set
the cookie, the browser discarded it, and the next request arrived
unauthenticated. The flag now follows the request scheme, so plain HTTP on a LAN
signs in normally.
If you are on a newer version and still looping, the usual cause is a reverse
proxy that terminates TLS without telling the app. The browser is on https://,
the app sees http://, and it issues a cookie the browser then treats
inconsistently. Set:
Network__UseForwardedHeaders=true
Network__TrustedNetworks__0=172.16.0.0/12 # or your proxy's address
X-Forwarded-Proto is what tells the app the original request was HTTPS. The
reverse proxy guide has working configs — and the same
setting stops your audit trail recording the proxy instead of the caller.
To separate a cookie problem from a credentials problem without changing anything,
tunnel in and use localhost, which browsers always treat as a secure origin:
ssh -L 8080:localhost:8080 you@the-host # then open http://localhost:8080
I can’t sign in / lost the admin account
Registration is locked after the first-run bootstrap, so you can’t simply re-register. Options:
- Sign in with another
agency_adminaccount and reset the user. - If no admin remains, you’ll need database access to promote an existing user:
docker compose exec -T postgres psql -U postgres -d dmarc_analyzer \ -c "update agency_user set \"Role\"='agency_admin' where \"Email\"='you@example.com';"
If you enabled SSO and it broke, this is why keeping one local admin password matters.
A domain landed under the wrong client
Domains are auto-created under the mailbox source’s default client. Reassign the domain from the Domains page, and change the mailbox’s default client so future domains land correctly.
Cross-tenant requests return 404, not 403
Deliberate. A client_viewer requesting another client’s data gets 404 so the
API never confirms that a resource exists. Not a bug — if you’re seeing unexpected
404s, check the user’s client grants.
Getting help
Include the sync-run counters and the relevant docker compose logs excerpt when
filing an issue —
and please redact domain names and credentials.
On this page
- No reports are arriving
- Mailbox authentication fails
- The worker isn’t ingesting anything
- ”Another worker already holds the ingestion lock”
- Kubernetes: pods restart a few times on first install
- Parse failures in the sync history
- The dashboard looks empty but reports imported
- The login form accepts my password and returns me to the login page
- I can’t sign in / lost the admin account
- A domain landed under the wrong client
- Cross-tenant requests return 404, not 403
- Getting help
On this page
- No reports are arriving
- Mailbox authentication fails
- The worker isn’t ingesting anything
- ”Another worker already holds the ingestion lock”
- Kubernetes: pods restart a few times on first install
- Parse failures in the sync history
- The dashboard looks empty but reports imported
- The login form accepts my password and returns me to the login page
- I can’t sign in / lost the admin account
- A domain landed under the wrong client
- Cross-tenant requests return 404, not 403
- Getting help