SENTRY_AUTH_TOKEN returns 401 — sourcemap upload silently broken #5
Labels
No labels
dependencies
major
security-pin
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
trails-cool/trails#5
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Production builds log:
This does not fail the build.
sentry-vite-pluginreports the error and the build continues, so images ship fine — but sourcemaps are never uploaded and production stack traces stay unsymbolicated. It went unnoticed for exactly that reason.The token was rotated on 2026-07-25 and the new value is confirmed committed (
f575eaereplaced the line ininfrastructure/secrets.app.env) and used by the production build — it still 401s. So the token itself is wrong, not the plumbing.Likely fix
sentry-clidoes two things here:releases newandsourcemaps upload. Both need release write.project:releases(plusorg:read)Update with
sops infrastructure/secrets.app.env. Nothing to change on the Forgejo side — CD decrypts it withAGE_SECRET_KEYand passes it as a BuildKit secret (which is also why it never lands in the image).Follow-up worth doing
Make the build fail when the Sentry upload fails, so this cannot rot silently again.
Status on 2026-09-11: still broken, and two causes are now eliminated
The most recent production deploy (
cd-appsrun 1459, commit7968b49) shows the same error for the journal and for the planner:The token has not changed since this issue was written. The ciphertext of
SENTRY_AUTH_TOKENininfrastructure/secrets.app.envlast changed inf575eae(2026-07-25). It is the same atmaintoday.Eliminated: the scope theory in the description above
Insufficient scopes give 403 Forbidden. This is 401 Invalid token. The two are different failures. The description names scopes as the likely fix, so please do not start there.
Eliminated: the data region
The org is in the EU region. Every DSN in the repository has an
o4509530546634752.ingest.de.sentry.iohost. Butsentry-clisends all API calls tohttps://sentry.iounless you configure a different URL, and noSENTRY_URLwas set anywhere in the repository. This looked decisive.PR #140 set
url: "https://de.sentry.io"inapps/journal/vite.config.tsandapps/planner/vite.config.ts. It merged as7968b49. Run 1459 rebuilt the#24build layer (the layer was not cached, so the new configuration applied), and the error did not change. The EU endpoint also rejects the token.That line is correct and it stays, but it was not the cause.
Eliminated: ambiguous extraction in the workflow
cd-apps.ymlreads the token with an unanchored match:Two matching keys would concatenate into one invalid value. Only one key in
secrets.app.envcontains that substring, so the extraction gives one value.What remains
The token value itself is wrong. It is revoked, or mistyped, or it has quotation marks that
cut -d= -f2-copies into the authorization header. All three give the same 401.Recommended fix
Rotate the token instead of diagnosing it further. Make an Organization Auth Token (Sentry → Settings → Auth Tokens) and write it with
sops infrastructure/secrets.app.env. This token type carries its own region URL and the necessary permissions, so it removes all remaining causes together. Make sure the value has no quotation marks around it.To identify the cause before you rotate, decrypt the file and read the prefix:
sntrys_is an organization token,sntryu_is a legacy user token, and any other prefix means the value is damaged.The follow-up is more important than before
A failed upload still does not fail the build.
sentry-vite-pluginreports the error and the build continues, and run 1459 finished green with two 401s in its log. This is why the problem stayed hidden for six weeks, and it is why it can happen again after the rotation. Please keep this issue open for that change.Root cause found: the token never reached the build
The token is correct. My two earlier theories were both wrong, and so was the original description. PR #143 has the fix.
docker/build-push-actionhas two different inputs:secrets:takes literal valuessecret-files:takes pathsBoth CD workflows used the first one with a path:
So the build received the 17-character string
/tmp/sentry_tokenas the token itself. The Dockerfile read it out of/run/secrets/,sentry-clisent it as the credential, and Sentry answeredInvalid token (http status: 401). The answer was correct. The decrypted token never entered the build.The build log shows it:
That
srcis a temp file that the action made for the literal value. Withsecret-files:,srcpoints at/tmp/sentry_tokenitself.The measurement that broke the deadlock
The stored token answers 200 on both endpoints:
Its value is 71 characters (
sntryu_+ 64 hex), with no quotation marks. So the credential is good, the file is good, and thegrep/cutextraction is good. Only the transport was left.Full record of eliminated theories
de.sentry.io; the 401 did not changegrepsecrets.app.envsecrets:used wheresecret-files:was neededWhat #140 got wrong
That PR pinned
url: "https://de.sentry.io"and said the region was the cause. It was not. The 401 did not move because the token was absent, whatever URL was used. #143 keeps the pin, because our org is in the EU and the pin costs nothing, but it rewrites the comment to say the pin is defensive.This issue stays open
A failed upload still does not fail the build. Run 1459 finished green with two 401s in its log. Until that changes, the next broken upload will also go unseen. That follow-up is the remaining work here.