You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Kiro's GenerateAssistantResponse backend rejects requests from AWS Builder
ID / social-login accounts with 400 ValidationException: profileArn is required for this request for at least claude-opus-5 and claude-sonnet-5. No local store ever caches a profileArn for that account
type, resolveKiroProfileArn() in src/oauth/kiro.ts only reads a cached
value, and src/adapters/kiro.ts's build() silently omits profileArn
from the wire payload when nothing was cached — so every request from a
Builder ID account against those models fails.
I expected the request to either succeed (matching what the official kiro-cli does for the same account) or fail with a clearer, provider-level
error rather than a raw upstream ValidationException.
Investigation update — a candidate fix I proposed below turned out to be
insufficient; see "What I tried" for why. Filing as a bug report with the
open question rather than a verified fix.
Reproduction
Configure the kiro provider with authMode: oauth, importing a
Builder-ID (not IAM Identity Center) kiro-cli session — not an API key
(ksk_...) login.
POST /v1/chat/completions with "model": "kiro/claude-opus-5" (or claude-sonnet-5) and any prompt.
Observe:
Provider error 400: Kiro invalid request:
com.amazon.kiro.runtimeservice#ValidationException: profileArn is required for this request.
Debug logging (OCX_DEBUG=1) on the failing request:
This only returns a profileArn if one is already cached in account
metadata, the KIRO_PROFILE_ARN env var, or the locally imported kiro-cli
credential. For a Builder ID account none of these exist — the OAuth account
metadata opencodex stores for Kiro is {ssoRegion, apiRegion, clientId, clientSecret} with no profileArn field, and the local kiro-cli SQLite
store (~/.local/share/kiro-cli/data.sqlite3) has no row for api.codewhisperer.profile either.
src/adapters/kiro.ts (build(), ~line 1699) treats the absence of a
cached profileArn as proof the account doesn't need one:
That assumption holds for most models but not for the ones Kiro gates
server-side.
What I tried (fix candidate — insufficient, do not merge as-is)
Initial (wrong) theory:strings on the kiro-cli 2.16.0 binary surfaced
a literal profile ARN compiled into fig_api_client::profile_resolver::ProfileResolver::for_builder_id, and a
trace-level (KIRO_LOG_LEVEL=trace) kiro-cli run showed that exact ARN
attached to every outgoing request on my test account, including ListAvailableModels. No ListAvailableProfiles RPC ever fires in the
trace on either run described below. I concluded this was a single
constant, shared by every Builder ID account, and proposed hardcoding it as
a fallback in the adapter (diff below, KIRO_PROFILE_PLACEHOLDER stands in
for the literal value from that binary).
Falsified by a second, independent account. I logged a second,
unrelated Builder ID/social-login account into kiro-cli 2.16.0 on a
separate machine and ran the same trace. That account's kiro-cli attached
a different profile ARN — different AWS account-id component and
different profile-id component — from the one on the first account, again
with no ListAvailableProfiles call in the trace. That rules out "one
shared constant for all Builder ID accounts." The mechanism kiro-cli uses
to arrive at a per-account profile with no visible RPC is still unknown to
me — possibly derived from claims already present in the OAuth/OIDC token,
possibly returned inline during token exchange rather than a separate call.
I have not yet confirmed either.
Net: the "hardcode a shared default ARN" fix is wrong. It would send one
account's real profile ARN as a blanket fallback for every other Builder ID
account, which is not obviously safer than omitting profileArn entirely
(today's behavior) and could plausibly cause Kiro's backend to associate a
request with the wrong profile rather than just reject it.
Diff as proposed (do not merge without resolving the above):
--- a/src/adapters/kiro.ts+++ b/src/adapters/kiro.ts
@@ constants near line 55
const KIRO_FALLBACK_SERIALIZATION_ENVELOPE_BYTES = 64 * 1024;
+const KIRO_BUILDER_ID_DEFAULT_PROFILE_ARN = "<KIRO_PROFILE_PLACEHOLDER>";
type KiroWireClient = "ide" | "cli";
@@ inside build(), ~line 1697
const region = resolveKiroApiRegion(parsed._kiroAuthContext);
const resolvedProfileArn = resolveKiroProfileArn(parsed._kiroAuthContext);
const isApiKey = provider.apiKey.trim().startsWith("ksk_");
- const profileArn = isApiKey ? undefined : resolvedProfileArn;
// wireClient must key off the ORIGINAL lookup, not the fallback below.
- const wireClient: KiroWireClient = isApiKey || !profileArn ? "cli" : "ide";+ const wireClient: KiroWireClient = isApiKey || !resolvedProfileArn ? "cli" : "ide";+ const profileArn = isApiKey ? undefined : (resolvedProfileArn ?? KIRO_BUILDER_ID_DEFAULT_PROFILE_ARN);
Client or integration
Direct HTTP/API client (also reachable via Codex CLI once opencodex
injects its openai_base_url)
Area
Provider adapter / Authentication and account pool
Version
2.10.0 (@bitkyc08/opencodex)
Operating system
Linux (Ubuntu, x86_64) — reproduced on two separate machines/accounts, same
OS family
Provider and model
kiro / claude-opus-5, claude-sonnet-5 (confirmed affected); a model not
requiring a profileArn (gpt-5.6-terra) shows no equivalent failure on the
same account, so this is model-specific on Kiro's side, not account-wide.
Logs or error output
Failing request (before any change):
$ curl -s -X POST http://127.0.0.1:PORT/v1/chat/completions \
-d '{"model":"kiro/claude-opus-5","messages":[{"role":"user","content":"Say OK"}],"reasoning_effort":"high"}'
{"error":{"message":"Provider error 400: Kiro invalid request: com.amazon.kiro.runtimeservice#ValidationException: profileArn is required for this request.","type":"invalid_request_error","param":null,"code":"invalid_request_error"}}
I removed secrets, tokens, account details, request credentials, and
personal data. Specifically: no AWS account IDs, no Kiro profile IDs, no
OAuth/access/refresh tokens, no email addresses, no hostnames/ports/paths
from any machine used to reproduce this appear anywhere above — all such
values are replaced with placeholders (<AWS_ACCOUNT_ID_PLACEHOLDER>, <KIRO_PROFILE_PLACEHOLDER>, PORT) even where they were plausible
evidence for the bug, because two independently-tested accounts produced
two different values for both fields and neither is reliably distinguishable
from account-identifying data without a byte-level audit I'm not confident
in giving a hard guarantee on.
Summary
Kiro's
GenerateAssistantResponsebackend rejects requests from AWS BuilderID / social-login accounts with
400 ValidationException: profileArn is required for this requestfor at leastclaude-opus-5andclaude-sonnet-5. No local store ever caches aprofileArnfor that accounttype,
resolveKiroProfileArn()insrc/oauth/kiro.tsonly reads a cachedvalue, and
src/adapters/kiro.ts'sbuild()silently omitsprofileArnfrom the wire payload when nothing was cached — so every request from a
Builder ID account against those models fails.
I expected the request to either succeed (matching what the official
kiro-clidoes for the same account) or fail with a clearer, provider-levelerror rather than a raw upstream
ValidationException.Investigation update — a candidate fix I proposed below turned out to be
insufficient; see "What I tried" for why. Filing as a bug report with the
open question rather than a verified fix.
Reproduction
kiroprovider withauthMode: oauth, importing aBuilder-ID (not IAM Identity Center)
kiro-clisession — not an API key(
ksk_...) login.POST /v1/chat/completionswith"model": "kiro/claude-opus-5"(orclaude-sonnet-5) and any prompt.Debug logging (
OCX_DEBUG=1) on the failing request:For comparison, the official
kiro-cli(v2.16.0) against the same accountsucceeds on the same model:
Root cause
src/oauth/kiro.ts—resolveKiroProfileArn():This only returns a
profileArnif one is already cached in accountmetadata, the
KIRO_PROFILE_ARNenv var, or the locally importedkiro-clicredential. For a Builder ID account none of these exist — the OAuth account
metadata
opencodexstores for Kiro is{ssoRegion, apiRegion, clientId, clientSecret}with noprofileArnfield, and the localkiro-cliSQLitestore (
~/.local/share/kiro-cli/data.sqlite3) has no row forapi.codewhisperer.profileeither.src/adapters/kiro.ts(build(), ~line 1699) treats the absence of acached
profileArnas proof the account doesn't need one:That assumption holds for most models but not for the ones Kiro gates
server-side.
What I tried (fix candidate — insufficient, do not merge as-is)
Initial (wrong) theory:
stringson thekiro-cli2.16.0 binary surfaceda literal profile ARN compiled into
fig_api_client::profile_resolver::ProfileResolver::for_builder_id, and atrace-level (
KIRO_LOG_LEVEL=trace)kiro-clirun showed that exact ARNattached to every outgoing request on my test account, including
ListAvailableModels. NoListAvailableProfilesRPC ever fires in thetrace on either run described below. I concluded this was a single
constant, shared by every Builder ID account, and proposed hardcoding it as
a fallback in the adapter (diff below,
KIRO_PROFILE_PLACEHOLDERstands infor the literal value from that binary).
Falsified by a second, independent account. I logged a second,
unrelated Builder ID/social-login account into
kiro-cli2.16.0 on aseparate machine and ran the same trace. That account's
kiro-cliattacheda different profile ARN — different AWS account-id component and
different profile-id component — from the one on the first account, again
with no
ListAvailableProfilescall in the trace. That rules out "oneshared constant for all Builder ID accounts." The mechanism
kiro-cliusesto arrive at a per-account profile with no visible RPC is still unknown to
me — possibly derived from claims already present in the OAuth/OIDC token,
possibly returned inline during token exchange rather than a separate call.
I have not yet confirmed either.
Net: the "hardcode a shared default ARN" fix is wrong. It would send one
account's real profile ARN as a blanket fallback for every other Builder ID
account, which is not obviously safer than omitting
profileArnentirely(today's behavior) and could plausibly cause Kiro's backend to associate a
request with the wrong profile rather than just reject it.
Diff as proposed (do not merge without resolving the above):
Client or integration
Direct HTTP/API client (also reachable via Codex CLI once
opencodexinjects its
openai_base_url)Area
Provider adapter / Authentication and account pool
Version
2.10.0 (
@bitkyc08/opencodex)Operating system
Linux (Ubuntu, x86_64) — reproduced on two separate machines/accounts, same
OS family
Provider and model
kiro/claude-opus-5,claude-sonnet-5(confirmed affected); a model notrequiring a profileArn (
gpt-5.6-terra) shows no equivalent failure on thesame account, so this is model-specific on Kiro's side, not account-wide.
Logs or error output
Failing request (before any change):
Same request, same account, with the candidate fix applied (succeeds, but
see "What I tried" for why this specific fix is not safe to merge):
Redacted configuration
{ "adapter": "kiro", "baseUrl": "https://runtime.us-east-1.kiro.dev", "authMode": "oauth", "defaultModel": "kiro-auto" }Checks
personal data. Specifically: no AWS account IDs, no Kiro profile IDs, no
OAuth/access/refresh tokens, no email addresses, no hostnames/ports/paths
from any machine used to reproduce this appear anywhere above — all such
values are replaced with placeholders (
<AWS_ACCOUNT_ID_PLACEHOLDER>,<KIRO_PROFILE_PLACEHOLDER>,PORT) even where they were plausibleevidence for the bug, because two independently-tested accounts produced
two different values for both fields and neither is reliably distinguishable
from account-identifying data without a byte-level audit I'm not confident
in giving a hard guarantee on.