
Vercel環境で@ai-sdk/amazon-bedrockが「The security token included in the request is invalid」エラーになる原因と解決策
リテールアプリ共創部 マッハチームのるおんです。
Vercel AI SDKの@ai-sdk/amazon-bedrockを使ってAmazon Bedrockを呼び出す際、ローカル環境では問題なく動作するのに、Vercel環境にデプロイすると以下のエラーが発生するという問題に遭遇しました。
AI_APICallError: The security token included in the request is invalid
この問題の原因特定と解決に至るまでの過程を共有します。同じ問題で困っている方の参考になれば幸いです。
先に結論
原因
VercelはAWS_SESSION_TOKENなどのAWS関連環境変数を自動的に注入します。@ai-sdk/amazon-bedrockはsessionTokenを明示的に渡さない場合、この環境変数を自動的に読み取ります。その結果、永続的なIAMユーザー認証情報と無関係なセッショントークンが混在 し、認証エラーが発生します。
解決策
credentialProviderを使用して認証情報を明示的に提供し、環境変数の自動読み取りをバイパスします。
createAmazonBedrock({
region: "ap-northeast-1",
credentialProvider: async () => ({
accessKeyId,
secretAccessKey,
// sessionTokenは意図的に含めない
}),
});
以下、原因特定に至るまでの調査過程を詳しく説明します。
問題の概要
発生状況
- ローカル環境: 正常に動作 ✅
- Vercel環境: 認証エラーが発生 ❌
最初の判断
ローカル環境では同じ認証情報で正常に動作しているため、以下の可能性は除外できると判断しました。
- IAM権限不足: ローカルで動くなら権限は足りている
- 認証情報の期限切れ:
AKIAで始まる永続的なアクセスキーを使用しており、期限切れはない - 認証情報の誤り: ローカルで動くなら認証情報自体は正しい
つまり、Vercel環境特有の何かが原因 であると推測し、調査を進めました。
使用していた構成
- Next.js 16.0.7
ai(Vercel AI SDK) v5.0.113@ai-sdk/amazon-bedrockv3.0.70@aws-sdk/client-s3v3.772.0(S3は正常に動作していた)- IAMユーザーの永続的な認証情報(
AKIAで始まるアクセスキー)
実装コード
Vercelの予約環境変数との競合を避けるため、カスタムの環境変数名(MY_AWS_*)を使用していました。
createAmazonBedrock({
region: "ap-northeast-1",
accessKeyId, // MY_AWS_ACCESS_KEY_IDから取得
secretAccessKey, // MY_AWS_SECRET_ACCESS_KEYから取得
});
原因調査の過程
1. 認証情報の確認
まず、Vercel上で認証情報が正しく渡されているかを確認するため、デバッグログを追加しました。
console.log("[DEBUG] Amazon Bedrock Client", {
accessKeyIdExists: !!accessKeyId,
accessKeyIdLength: accessKeyId?.length ?? 0,
accessKeyIdPrefix: accessKeyId?.substring(0, 4) ?? "N/A",
secretAccessKeyExists: !!secretAccessKey,
secretAccessKeyLength: secretAccessKey?.length ?? 0,
});
結果は問題なし。AKIAで始まる20文字のアクセスキーIDと40文字のシークレットアクセスキーが正しく渡されていました。
2. CloudTrailでの確認
AWS CloudTrailでBedrockのAPIコールログを確認したところ、成功したリクエストしか記録されていませんでした。認証エラーのリクエストはCloudTrailに記録される前にAWSによって拒否されていることがわかりました。
3. 環境変数の調査
ai-sdkのソースコードを調査したところ、重要な発見がありました。
return {
accessKeyId: loadSetting({
settingValue: options.accessKeyId,
environmentVariableName: "AWS_ACCESS_KEY_ID",
}),
secretAccessKey: loadSetting({
settingValue: options.secretAccessKey,
environmentVariableName: "AWS_SECRET_ACCESS_KEY",
}),
sessionToken: loadOptionalSetting({
settingValue: options.sessionToken,
environmentVariableName: "AWS_SESSION_TOKEN" // ← ここが問題!
})
};
sessionTokenを明示的に渡していない場合、SDKは自動的にAWS_SESSION_TOKEN環境変数を読み取ります。
4. 原因特定
Vercel上で環境変数を確認するログを追加しました。
console.log("[DEBUG] Environment check", {
AWS_SESSION_TOKEN_exists: !!process.env.AWS_SESSION_TOKEN,
AWS_SESSION_TOKEN_length: process.env.AWS_SESSION_TOKEN?.length ?? 0,
});
結果:
AWS_SESSION_TOKEN_exists: true
AWS_SESSION_TOKEN_length: 996
Vercelが自動的にAWS_SESSION_TOKENを注入していました!
原因の詳細
何が起きていたのか
- カスタム環境変数(
MY_AWS_*)から永続的なIAMユーザーの認証情報を取得 createAmazonBedrockにaccessKeyIdとsecretAccessKeyを明示的に渡す- しかし
sessionTokenは渡していない - ai-sdkの
loadOptionalSettingがAWS_SESSION_TOKEN環境変数を自動的に読み取る - Vercelが注入した無関係なセッショントークン(Vercelインフラ用)が使われる
- 永続的IAMユーザー認証情報 + 無関係なセッショントークン = 認証エラー
なぜローカルでは動いたのか
ローカル環境ではAWS_SESSION_TOKEN環境変数が設定されていなかったため、loadOptionalSettingはundefinedを返し、セッショントークンなしでリクエストが送信されていました。
Vercelの公式ドキュメントの記載
VercelのReserved environment variablesには以下の記載があります。
一部のAWS関連環境変数は、明示的に設定しなくてもVercel Functionsに自動的に現れることがあります。ただし、これらはAWS権限を持たず、認証情報として使用できません。
しかし、ai-sdkはこれを知らずに自動的に読み取ってしまうのです。
解決策
credentialProviderを使用する
credentialProviderを使用することで、環境変数の自動読み取りを完全にバイパスできます。
createAmazonBedrock({
region: "ap-northeast-1",
credentialProvider: async () => ({
accessKeyId,
secretAccessKey,
// sessionTokenは意図的に含めない
}),
});
なぜこれで解決するのか
ai-sdkのソースコードを見ると、credentialProviderが指定されている場合はloadSetting/loadOptionalSettingが呼ばれません。
if (options.credentialProvider) {
return {
...await options.credentialProvider(), // ← 環境変数を見ない
region
};
}
// credentialProviderがない場合のみ環境変数を読み取る
関連するGitHub Issues
この問題に関連するIssueがいくつか存在します。
- Issue #3018: AWS Bedrock provider doesn't work unless using bedrockOptions
- Issue #2780: Bedrock credential chain environment variables
Issue #3018ではbedrockOptionsを使った回避策が提案されていますが、現在のバージョン(v3.0.73)ではbedrockOptionsは認証情報用ではなく、モデルオプション用(reasoningConfig、anthropicBeta等)に使われています。
まとめ
問題
Vercelが自動注入するAWS_SESSION_TOKENとai-sdkの環境変数自動読み取りが競合し、認証エラーが発生する。
解決策
credentialProviderを使用して認証情報を明示的に提供し、環境変数の自動読み取りをバイパスする。
createAmazonBedrock({
region: "ap-northeast-1",
credentialProvider: async () => ({
accessKeyId,
secretAccessKey,
}),
});
教訓
- ローカルと本番で環境変数が異なる可能性を常に意識する
- SDKの内部実装(環境変数の自動読み取り等)を理解しておく
- CloudTrailに記録されないエラーも存在する(署名検証失敗など)
おわりに
この問題は、ローカルでは動くのに本番では動かないという厄介なパターンでした。原因特定には環境変数のデバッグログが非常に有効でした。
同じ問題で困っている方の参考になれば幸いです。
参考








