Nothing is showing up
Every failure on this page is one we have actually hit. They share a shape: nothing errors. The plugin reports no problem, the dashboard renders fine, and the data simply is not there. So the fastest route is not to read logs β it is to work down this list in order.
Start here: three checks, about a minute
1. Is the API healthy?
curl https://api.sentrinel.dev/health
{
"status": "ok",
"databaseHealthy": true,
"schemaReady": true,
"telemetryStore": "clickhouse",
"telemetryHealthy": true
}
Every field must be true. What each one failing means:
| Field | If false |
|---|---|
databaseHealthy |
The API cannot reach Postgres. Nobody can sign in. Check DATABASE_URL. |
schemaReady |
Migrations did not apply. Every authenticated route will 500. Check the API logs at boot. |
telemetryHealthy |
The telemetry store is unusable. Metrics may still write, but reads 500. Usually credentials, not the network. |
status: "degraded" means one of them is false. The HTTP code stays 200 when
only telemetry is down β restarting the API cannot fix ClickHouse, and failing
the health check would take auth down with it.
2. Is your serverUrl the API, and not the dashboard?
serverUrl: "https://api.sentrinel.dev" // β
the API
serverUrl: "https://app.sentrinel.dev" // β the dashboard
The dashboard is static files on a CDN. It has no ingest endpoint, so telemetry sent there disappears into a 404 that the plugin does not treat as a misconfiguration. This is the single most common cause of "I set it up and nothing happened."
3. Is request logging turned on?
sentrinelPlugin({
// β¦
requestLogging: { enabled: true },
})
It is off by default. With it off you still get charts, endpoint tables and error rates β those come from in-process counters β but Request logs, request detail, payloads and the trace links are all permanently empty. The result looks like a half-broken product rather than an unset option.
Symptom: charts have data, Request logs is empty
Request logging is off. See check 3 above. Aggregated metrics and individual
request rows travel on different paths β counters are computed in your process
and flushed as rollups; rows are only sent when requestLogging.enabled is true.
If it is on, check sampleRate. At 0.1 you keep one in ten successful
requests. Errors and slow requests are never sampled out, so a page showing only
failures is the expected look of a low sample rate, not a bug.
Symptom: nothing at all, and the plugin is silent
Work through these in order.
The key does not match the app. Ingest requires that the API key, appName
and env all belong to the same app. A mismatch is a 403, which the plugin
reports once β check your process output for a Sentrinel warning at startup.
appName: "checkout-api" // must equal the app's name exactly
env: "prod" // must equal the key's environment
Renaming an app in the dashboard without updating appName breaks ingest
silently from the next flush onward.
You are using the row id instead of the key. POST /api/apikeys returns
both, and they are easy to swap:
{ "key": "β¦row uuidβ¦", "secretKey": "snt_live_β¦" }
secretKey is the credential. key is the database row id and will be rejected
as an invalid API key.
The process exited before a flush. The default flushInterval is 30s. A
short-lived script or a container that stops immediately may never flush. Call
await flush() before exit, or lower the interval.
Symptom: logs appear, but they are not attached to a request
The link is carried by a field whose name differs between record types, and using the wrong one fails silently β the record still inserts and still shows up in its list. Only the link is missing.
| Record | Field |
|---|---|
| Log | requestId |
| Error | requestLogId |
Both SDKs send the right one. If you are posting to the ingest API yourself, this is worth double-checking. The API accepts either spelling on both endpoints for exactly this reason, but the table above is the documented shape.
Symptom: a trace opens but has no spans
Each span carries its own id, and the field is id β not spanId:
{ "spans": [ { "id": "0011223344556677", "name": "db.query" } ] }
A span without id is rejected with a 400 naming the field. Spans come from
traceSpan(); a request with no instrumented work inside it produces a trace
with only its root span, which is normal.
Symptom: signing in fails, or the dashboard says the API returned an error
The sign-in page distinguishes two cases, and the wording tells you which:
- "No response from β¦" β nothing came back. DNS, TLS, the service being
down, or your origin missing from
SENTRINEL_ALLOWED_ORIGINS. - "β¦ is up but returned an error" β the API answered with a 5xx. This is the
API or its database, not your credentials. Check
/healthfirst.
Symptom: everything was working, then stopped after a deploy
Check that the running container actually picked up its configuration. A stored config that was corrected but never redeployed leaves the old value running:
docker service inspect sentrinel-api \
--format '{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{println .}}{{end}}' \
| grep -c DATABASE_URL
Compare what the platform stores against what the container has. They can disagree, and the container is what runs.
Still stuck?
Turn on plugin logging and watch one flush:
sentrinelPlugin({ /* β¦ */ debug: true, flushInterval: 2000 })
The plugin prints what it sends and, on a rejected batch, the server's own
explanation. A batch rejected with 401 or 403 is always a key, appName or
env mismatch β never a network problem.