ggshield "401 Unauthorized" from the GitGuardian API in CI
A 401 from the GitGuardian API means the request reached the service but the key was not accepted: it is expired, revoked, or does not carry the scan scope. The key format is fine; its authorization is not.
What this error means
ggshield fails with "Unexpected error: 401" or "401 Unauthorized" from the API, unlike an "Invalid API key" that never leaves the client.
Error: 401 Unauthorized
The server returned: {"detail":"Invalid or expired token."}Common causes
The API key is expired or revoked
A rotated or time-limited GitGuardian token that has passed its expiry is rejected with 401 even though it is well formed.
The key lacks the scan scope
A personal access token without the scan scope authenticates but is not authorized to run secret scans, returning 401.
How to fix it
Issue a new key with the scan scope
- Create a fresh GitGuardian API key that includes the
scanscope. - Update the CI secret with the new value.
- Re-run and confirm
ggshield api-statusreports the key as valid.
ggshield api-status
# expected: API key: validRotate on a schedule in one place
Store the key once as a secret and rotate it there so an expired token does not silently break every workflow.
How to prevent it
- Grant the scan scope when creating GitGuardian keys.
- Track key expiry and rotate before it lapses.
- Store the key in a single CI secret to rotate in one place.