Skip to content

Image tool fails with Bedrock + aws-sdk auth mode — missing carve-out in requireApiKey #77397

Description

@bstanbury

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

  1. Configure agents.defaults.imageModel.primary = amazon-bedrock/us.anthropic.claude-opus-4-7 (or any Bedrock model).
  2. Ensure the Bedrock provider's auth.mode is "aws-sdk" and auth.apiKey is unset.
  3. Ensure AWS creds are available to the openclaw process via ~/.aws/credentials or env vars (but not as a pasted apiKey).
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions