Summary
kbagent token create against a project on the europe-west3.gcp (EU GCP) stack fails every time with a raw 500 from the Keboola Storage API. Investigation shows kbagent itself is behaving correctly (correct request, retries per its documented policy, faithfully surfaces the upstream error) — this looks like an upstream Storage API defect, not a kbagent bug. Filing here anyway because (a) kbagent is the only way I have to observe/reproduce it, and (b) there's a concrete CLI-side hardening gap exposed by it (see "Proposal").
Environment
kbagent v0.84.2 (keboola-cli PyPI package)
- Stack:
connection.europe-west3.gcp.keboola.com
Repro
kbagent -v token create -p <project> -d "<description>" --expires-in 60
Response: 500 {"error": "Application error."} from POST /v2/storage/tokens, retried 3x by kbagent's existing backoff policy (500 is in RETRYABLE_STATUS_CODES), all 3 attempts fail identically.
Ruled out as the cause, so this doesn't look like a request-shape bug on the client side:
- Reproduces on 2 different projects on the same stack, with 2 different acting tokens.
- Reproduces with no scope, and with
--bucket-read on a real bucket.
- Reproduces with
--expires-in 60, --expires-in 3600, and omitted entirely (never expires).
- Acting token confirmed to have
canManageTokens — rules out the missing-permission theory (which per http_base.py's own _raise_api_error should surface as a clean 403 → ErrorCode.ACCESS_DENIED, not a 500).
- No incident reported for the
europe-west3 stack on status.keboola.com / keboolastatus.com at the time of testing.
Proposal
Not asking for a fix to the upstream API from this repo — that's a Keboola Connection backend issue I'll raise with Keboola support separately. But two things are actionable in kbagent itself:
- Non-idempotent retry risk:
POST /v2/storage/tokens is a create/mint call, not idempotent, yet it's retried on 500/502/503/504 like any other request. If the API ever creates the token server-side and then fails to respond cleanly (unlike this case, where all 3 attempts failed identically with no sign of partial success), a blind retry could silently mint a duplicate live credential the caller never sees. Worth excluding mutating/non-idempotent endpoints from the generic retry policy, or gating the retry on an idempotency key.
- Generic 500 message gives no next step: today this surfaces as
API error 500 ... Application error. with no hint that a persistent 500 (survives all retries, stable across projects/tokens/payloads) is very likely an upstream incident rather than something the caller can fix. A short, specific hint in the ErrorCode.API_ERROR 500 path (e.g. "if this persists across retries/projects, it's likely an upstream Keboola incident — contact Keboola support") would save the next person the same investigation.
Open questions
- Is there a better internal channel (Keboola support / a status page not covered by status.keboola.com or keboolastatus.com) that kbagent maintainers already use to escalate confirmed upstream 500s like this one? If so, pointing to it from the error message would be more useful than a generic hint.
Summary
kbagent token createagainst a project on theeurope-west3.gcp(EU GCP) stack fails every time with a raw500from the Keboola Storage API. Investigation shows kbagent itself is behaving correctly (correct request, retries per its documented policy, faithfully surfaces the upstream error) — this looks like an upstream Storage API defect, not a kbagent bug. Filing here anyway because (a) kbagent is the only way I have to observe/reproduce it, and (b) there's a concrete CLI-side hardening gap exposed by it (see "Proposal").Environment
kbagentv0.84.2 (keboola-cliPyPI package)connection.europe-west3.gcp.keboola.comRepro
Response:
500 {"error": "Application error."}fromPOST /v2/storage/tokens, retried 3x by kbagent's existing backoff policy (500 is inRETRYABLE_STATUS_CODES), all 3 attempts fail identically.Ruled out as the cause, so this doesn't look like a request-shape bug on the client side:
--bucket-readon a real bucket.--expires-in 60,--expires-in 3600, and omitted entirely (never expires).canManageTokens— rules out the missing-permission theory (which perhttp_base.py's own_raise_api_errorshould surface as a clean403→ErrorCode.ACCESS_DENIED, not a500).europe-west3stack on status.keboola.com / keboolastatus.com at the time of testing.Proposal
Not asking for a fix to the upstream API from this repo — that's a Keboola Connection backend issue I'll raise with Keboola support separately. But two things are actionable in kbagent itself:
POST /v2/storage/tokensis a create/mint call, not idempotent, yet it's retried on 500/502/503/504 like any other request. If the API ever creates the token server-side and then fails to respond cleanly (unlike this case, where all 3 attempts failed identically with no sign of partial success), a blind retry could silently mint a duplicate live credential the caller never sees. Worth excluding mutating/non-idempotent endpoints from the generic retry policy, or gating the retry on an idempotency key.API error 500 ... Application error.with no hint that a persistent 500 (survives all retries, stable across projects/tokens/payloads) is very likely an upstream incident rather than something the caller can fix. A short, specific hint in theErrorCode.API_ERROR500 path (e.g. "if this persists across retries/projects, it's likely an upstream Keboola incident — contact Keboola support") would save the next person the same investigation.Open questions