can1357/oh-my-pi · error · BedrockApiError

Bedrock HTTP ${response.status}: ${errBody.slice(0, 1000)}

Error message

Bedrock HTTP ${response.status}: ${errBody.slice(0, 1000)}

What it means

A BedrockApiError raised in streamBedrock when the Bedrock HTTP endpoint (event stream invocation) returns a non-success status. The message embeds the HTTP status and up to 1000 characters of the response body for diagnosis. For 401/403 without a bearer token, the AWS credential cache is invalidated first so the next attempt re-resolves credentials.

Source

Thrown at packages/ai/src/providers/amazon-bedrock.ts:488

					method: "POST",
					headers: requestHeaders,
					body,
					signal: watchdog.signal,
					fetch: options.fetch,
					timeout: false,
				});
			} finally {
				watchdog.clear();
			}

			if (!response.ok) {
				if (!bearerToken && (response.status === 401 || response.status === 403)) {
					// Stale cached credentials (e.g. rotated session keys in ~/.aws/credentials) —
					// drop the cache entry so the next attempt re-resolves from scratch.
					invalidateAwsCredentialCache({ profile: options.profile, region });
				}
				const errBody = await response.text().catch(() => "");
				throw new AIError.BedrockApiError(
					`Bedrock HTTP ${response.status}: ${errBody.slice(0, 1000)}`,
					response.status,
					{
						headers: response.headers,
					},
				);
			}
			if (!response.body) throw new AIError.BedrockApiError("Bedrock response has no body", response.status);

			// Track first event for the abort/diagnostic path (currently informational).
			for await (const message of decodeEventStream(response.body)) {
				const messageType = message.headers[":message-type"];
				const eventType = message.headers[":event-type"];

				if (messageType === "exception") {
					const exceptionType = message.headers[":exception-type"] || "Exception";
					const payload = safeParsePayload(message.payload) as { message?: string } | undefined;
					const errorMessage = payload?.message || new TextDecoder().decode(message.payload);

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the embedded body in the message — it contains Bedrock's actual error reason
  2. For 401/403: re-run aws sso login / refresh credentials; the cache is auto-invalidated but the current attempt still fails
  3. Verify IAM permissions for bedrock:InvokeModelWithResponseStream on the model ARN
  4. Confirm the model id and region are correct and the model is enabled in your account
  5. Implement retry with backoff for 429/5xx statuses

Example fix

// before
const res = await client.send(new InvokeModelWithResponseStreamCommand(input)); // throws on 403
// after
try {
  const res = await client.send(cmd);
} catch (e) {
  if (e instanceof AIError.BedrockApiError && e.status === 403) {
    await refreshAwsCredentials(); // then retry once
  } else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-check credentials and access before calling
const sts = new STSClient({ region });
await sts.send(new GetCallerIdentityCommand({})); // fails fast on bad creds
if (!bearerToken && (!process.env.AWS_PROFILE && !options.profile)) console.warn("no explicit AWS profile set");

Type guard

function isBedrockHttpError(e: unknown): e is AIError.BedrockApiError {
  return e instanceof AIError.BedrockApiError && /^Bedrock HTTP \d+/.test(e.message);
}

Try / catch

try {
  await streamBedrock(options);
} catch (e) {
  if (isBedrockHttpError(e)) {
    const status = e.status;
    if (status === 429 || status >= 500) return retryWithBackoff();
    if (status === 401 || status === 403) return refreshAwsCredsAndRetry();
  }
  throw e;
}

Prevention

When it happens

Trigger: Bedrock InvokeModelWithResponseStream returning 4xx/5xx; expired or rotated AWS session credentials causing 401/403; missing model access or wrong region giving 403/404; request throttling (429) or malformed request bodies (400).

Common situations: Stale ~/.aws/credentials after an SSO re-login; IAM policy lacking bedrock:InvokeModelWithResponseStream; model id not available in the selected region; quota exhaustion during bursts.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/6db09b4acc46f3a3. Report an issue: GitHub.