`LLM.complete()` re-runs `adapter.validate({**self.kwargs, **kwargs})`
on every call (llm.py:286). The first pass translates `aws_bearer_token`
into LiteLLM's `api_key` kwarg and pops both the bearer field and
`auth_type`, so the second pass sees:
- `api_key` present (output of first pass)
- no `aws_bearer_token` (popped)
- no `auth_type` (popped) → resolver falls into legacy mode
Pydantic's `model_dump()` only emits declared fields, and `api_key` was
not declared on `AWSBedrockLLMParameters` — so the second pass silently
dropped the token. LiteLLM then fell through to SigV4 signing, found no
AWS credentials, and 401'd with `Unable to locate credentials` (the
exact symptom reported when testing a bearer-token Bedrock adapter from
the UI).
Fix:
- Declare `api_key: str | None = None` on both bedrock parameter classes
so it survives Pydantic's round-trip. Embedding doesn't re-validate
today, but added for symmetry to defend against future regressions.
- Update the resolver to pop `api_key` in `iam_role` and `access_keys`
modes (drop stale tokens from previous bearer-mode kwargs) and to
pop a blank `api_key` (Pydantic's `None` default) in legacy mode while
preserving a non-blank one (the round-trip case the LLM path needs).
Two regression tests cover the round-trip path: the second
`validate()` call must keep `api_key` intact for both LLM and embedding
parameter classes. 37 tests pass.
What
Fix a bug introduced by #1952 (bearer-token Bedrock auth) where the bearer token is silently dropped on
LLM.complete()'s secondvalidate()call, causing the UI "Test Connection" action to fail withBedrockException Invalid Authentication - Unable to locate credentialsfor any Bedrock LLM adapter configured with Bedrock API Key (Bearer Token) auth.Why
LLM.complete()re-runsadapter.validate({**self.kwargs, **kwargs})on every call (unstract/sdk1/src/unstract/sdk1/llm.py:286). The first pass translatesaws_bearer_token→ LiteLLM'sapi_keykwarg and pops both the bearer field andauth_type, so the second pass sees:api_keypresent (output of the first pass)aws_bearer_token(popped)auth_type(popped) → resolver falls into legacy modePydantic's
model_dump()only emits declared fields, andapi_keywas not declared onAWSBedrockLLMParameters— so the second pass silently dropped the token. LiteLLM then fell through to SigV4 signing, found no AWS credentials, and 401'd withUnable to locate credentials(the exact UI-visible symptom).This was 100% reproducible in the UI: pick Bedrock API Key (Bearer Token) → paste a valid key → click Test Connection → fail.
How
api_key: str | None = Noneon bothAWSBedrockLLMParametersandAWSBedrockEmbeddingParametersso the field survives Pydantic'smodel_dump(). Embedding doesn't re-validate today, but the symmetric declaration defends against a future regression._resolve_bedrock_aws_credentialsto popapi_keyiniam_roleandaccess_keysmodes (drops Pydantic'sNonedefault, plus any staleapi_keyfrom a previous bearer-mode kwargs dict). In legacy mode, pop a blankapi_keywhile preserving a non-blank one — the round-trip case the LLM path needs.Can this PR break any existing features. If yes, please list possible items. If no, please explain why.
No. Validated against every non-bearer flow. Output kwargs are byte-identical to pre-fix:
access_keysiam_roleauth_type)bearer_tokenLLM.complete()re-validateAll 19 pre-existing access_keys / iam_role / legacy / stale-key tests still pass — they explicitly assert
"api_key" not in outfor non-bearer modes, so the resolver pop guarantees no regression.Database Migrations
None.
Env Config
None.
Relevant Docs
Related Issues or PRs
Dependencies Versions
None changed.
Notes on Testing
Run locally:
37 passed (35 pre-existing + 2 new round-trip regression tests):
test_llm_bearer_token_survives_revalidation— pins the LLM bug fix; secondvalidate()call must keepapi_keyintact.test_embedding_bearer_token_survives_revalidation— defensive parity for embedding.End-to-end smoke check (manual):
unstract/sdk1.access_keysandiam_roleadapters to confirm no regression.Screenshots
The UI failure screenshots were attached to the bug report — re-testing them with this branch should show Test Connection passing instead of the
Unable to locate credentialstoast.Checklist
I have read and understood the Contribution Guidelines.