Summary
The image tool refuses to run on any Bedrock model when the provider is configured with auth.mode: "aws-sdk" and credentials live in ~/.aws/credentials / env vars rather than being pasted into the config as apiKey.
The text / main-loop code path already has the correct carve-out — it passes undefined as the API key and lets the AWS SDK resolve credentials from its usual chain (env → shared credentials → IMDS → SSO). The image code path does not; it calls requireApiKey() unconditionally, which throws.
Net effect: text chat works, vision is broken, even though both target the exact same Bedrock model.
Environment
- OpenClaw: 2026.4.20 (
systemctl status openclaw)
- Host: Linux 6.17.0-23-generic (Ubuntu 25.10, x86_64)
- Node: v22.22.2
- Install: npm global,
/usr/lib/node_modules/openclaw
- Bedrock provider:
auth.mode: "aws-sdk", no pasted apiKey
- Credentials:
~/.aws/credentials (valid, works for aws bedrock list-foundation-models)
- Env:
AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY exported to the openclaw systemd unit via EnvironmentFile=-/etc/openclaw.env and visible in /proc/<pid>/environ
Reproduction
- Configure
agents.defaults.imageModel.primary = amazon-bedrock/us.anthropic.claude-opus-4-7 (or any Bedrock model).
- Ensure the Bedrock provider's
auth.mode is "aws-sdk" and auth.apiKey is unset.
- Ensure AWS creds are available to the openclaw process via
~/.aws/credentials or env vars (but not as a pasted apiKey).
- Call the
image tool with any image URL or path.
Observed:
All image models failed: amazon-bedrock/us.anthropic.claude-opus-4-7:
No API key resolved for provider "amazon-bedrock" (auth mode: aws-sdk). |
amazon-bedrock/us.anthropic.claude-sonnet-4-6: same error |
amazon-bedrock/us.anthropic.claude-opus-4-6-v1: same error.
Text chat targeting the same model works fine (it uses the carve-out below).
Root cause (tracing through dist/)
/usr/lib/node_modules/openclaw/dist/model-auth-runtime-shared-D2iI3D5p.js
function requireApiKey(auth, provider) {
const key = normalizeSecretInput(auth.apiKey);
if (key) return key;
throw new Error(`No API key resolved for provider "${provider}" (auth mode: ${auth.mode}).`);
}
requireApiKey only checks auth.apiKey — it does not fall through to env vars or ~/.aws/credentials even when auth.mode === "aws-sdk".
/usr/lib/node_modules/openclaw/dist/commands-handlers.runtime-BBSwQPFr.js:1271 — main-loop text handler has the correct carve-out:
let apiKey = apiKeyInfo.mode === "aws-sdk" && !apiKeyInfo.apiKey
? void 0 // skip requireApiKey for aws-sdk mode; the AWS SDK reads creds itself
: requireApiKey(apiKeyInfo, model.provider);
The image-tool code path, however, calls requireApiKey() unconditionally. Because apiKey is falsy, the throw fires before the AWS SDK ever gets a chance to use its native credential chain.
Suggested fix
Either mirror the carve-out in the image path, or (cleaner) push it into requireApiKey itself so every call-site gets it for free:
function requireApiKey(auth, provider) {
if (auth.mode === "aws-sdk") return undefined; // SDK handles creds
const key = normalizeSecretInput(auth.apiKey);
if (key) return key;
throw new Error(`No API key resolved for provider "${provider}" (auth mode: ${auth.mode}).`);
}
Moving it into requireApiKey would also prevent this class of bug from regressing the next time a new call-site is added.
Workarounds tried (all unsuccessful)
- Exporting
AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY to the process (confirmed visible in /proc/<pid>/environ).
SIGUSR1 config reload.
- Full
systemctl restart openclaw.
All fail at the same requireApiKey throw, because the check is on auth.apiKey, not env/shared creds.
Not attempting local patch
openclaw is managed through npm in this environment, so patching dist/ directly is lost on every upgrade. Filing upstream instead of maintaining a local carry.
Scope
This is a missing case, not a security bug. Users with auth.apiKey set (pasted token) are unaffected. Users using the AWS SDK credential chain — which is the documented / recommended pattern for Bedrock — hit it on every image call.
Summary
The
imagetool refuses to run on any Bedrock model when the provider is configured withauth.mode: "aws-sdk"and credentials live in~/.aws/credentials/ env vars rather than being pasted into the config asapiKey.The text / main-loop code path already has the correct carve-out — it passes
undefinedas the API key and lets the AWS SDK resolve credentials from its usual chain (env → shared credentials → IMDS → SSO). The image code path does not; it callsrequireApiKey()unconditionally, which throws.Net effect: text chat works, vision is broken, even though both target the exact same Bedrock model.
Environment
systemctl status openclaw)/usr/lib/node_modules/openclawauth.mode: "aws-sdk", no pastedapiKey~/.aws/credentials(valid, works foraws bedrock list-foundation-models)AWS_ACCESS_KEY_ID+AWS_SECRET_ACCESS_KEYexported to the openclaw systemd unit viaEnvironmentFile=-/etc/openclaw.envand visible in/proc/<pid>/environReproduction
agents.defaults.imageModel.primary = amazon-bedrock/us.anthropic.claude-opus-4-7(or any Bedrock model).auth.modeis"aws-sdk"andauth.apiKeyis unset.~/.aws/credentialsor env vars (but not as a pastedapiKey).imagetool with any image URL or path.Observed:
Text chat targeting the same model works fine (it uses the carve-out below).
Root cause (tracing through
dist/)/usr/lib/node_modules/openclaw/dist/model-auth-runtime-shared-D2iI3D5p.jsrequireApiKeyonly checksauth.apiKey— it does not fall through to env vars or~/.aws/credentialseven whenauth.mode === "aws-sdk"./usr/lib/node_modules/openclaw/dist/commands-handlers.runtime-BBSwQPFr.js:1271— main-loop text handler has the correct carve-out:The image-tool code path, however, calls
requireApiKey()unconditionally. BecauseapiKeyis falsy, the throw fires before the AWS SDK ever gets a chance to use its native credential chain.Suggested fix
Either mirror the carve-out in the image path, or (cleaner) push it into
requireApiKeyitself so every call-site gets it for free:Moving it into
requireApiKeywould also prevent this class of bug from regressing the next time a new call-site is added.Workarounds tried (all unsuccessful)
AWS_ACCESS_KEY_ID+AWS_SECRET_ACCESS_KEYto the process (confirmed visible in/proc/<pid>/environ).SIGUSR1config reload.systemctl restart openclaw.All fail at the same
requireApiKeythrow, because the check is onauth.apiKey, not env/shared creds.Not attempting local patch
openclaw is managed through npm in this environment, so patching
dist/directly is lost on every upgrade. Filing upstream instead of maintaining a local carry.Scope
This is a missing case, not a security bug. Users with
auth.apiKeyset (pasted token) are unaffected. Users using the AWS SDK credential chain — which is the documented / recommended pattern for Bedrock — hit it on every image call.