[認証モードがOAuthからAPIキーに自動切り替え] - Auth Mode Silently Switched from OAuth to API Key
ChatGPTモデルのGateway認証モードが予期せずOAuthからAPIキーモードに戻り、予期しないAPI quotaの消費とエージェントの無応答が発生しました。
🔍 症状
主なエラー現象
問題は連鎖的な障害シーケンスとして現れます:
# 最初の警告(07:34に7回以上ログ出力)
WARN [gateway] Config invalid; doctor will run with best-effort config.
# その後、認証モードのサイレント切り替えが発生(この遷移に対するログエントリなし)
# 後の14:36 - quotaの枯渇
ERROR [gateway] LLM request failed: OpenAI API error 429
{
"error": {
"type": "insufficient_quota",
"message": "You exceeded your current quota, please ensure you have provided your own API key."
}
}
# フォールバックの枯渇(14:43)
ERROR [gateway] Anthropic fallback failed: insufficient credits
{
"error": {
"type": "invalid_request_error",
"message": "Your credit balance is too low"
}
}
動作的症状
- 認証モードの移行: ユーザーが、手動の設定変更なしに、ゲートウェイがOAuth(ChatGPT Plusサブスクリプション)からAPIキーモードに切り替わったと報告しました。
- サイレント障害: 実際の認証モードの移行に対するログエントリが存在しないため、ログだけでは診断が不可能です。
- エージェントの応答なし: OpenAI quotaとAnthropicフォールバッククレジットの両方が枯渇すると、すべてのLLM操作が完全に失敗します。
- Doctor警告のスパム: 「Config invalid」メッセージが7回以上連続して表示され、doctorが繰り返し修復を試みる設定状態を繰り返し示しています。
環境コンテキスト
Gateway Version: v2026.2.17
Model: openai/gpt-5-chat-latest
Gateway Mode: local
Operating System: macOS (darwin)
Timeline: 2026-02-28 07:34 - 14:43
🧠 原因
技術的分析
根本原因は「doctor」回復メカニズムを引き起こした設定状態の破損にあり、doctorは設定が無効な場合に無条件にAPIキー認証にフォールバックします。
障害シーケンス
- 設定の無効化: 約07:34にゲートウェイ設定ファイルが無効または読み取り不能になりました。
- Doctor回復のトリガー:
doctorサブシステムが無効な設定を検出し、自動修復を開始しました。 - 認証モードのリセット: ベストエフォート型の回復中、doctorはOAuthトークンの永続化が回復パスで利用できなかったため、デフォルトで
auth_mode: api-keyとなる最小限の有効な設定を書き込みました。 - サイレント移行: 認証モードが
oauthからapi-keyに変更されましたが、認証の移行に対するログ記録がすでに失敗していた設定検証の背後にあるため、対応するログエントリはありません。 - Quotaの枯渇: 有効なAPIキーが設定されていない(または枯渇している)状態で、ゲートウェイは利用可能なQuotaを消費しようとした後、失敗しました。
アーキテクチャの問題
config/doctor.goにある重大なアーキテクチャ上の欠陥:
// 修正前(バグのある動作)
func (d *Doctor) repairConfig() error {
// 既存の設定を読み込んで設定を保持
cfg, err := d.loadConfig()
if err != nil {
// 設定が無効 - ゼロから開始
cfg = &Config{} // <-- 問題: デフォルトで空の設定を作成
}
// ... 修復ロジック ...
// 欠落: 認証モードの移行をログに記録
// 欠落: 前のセッションからのOAuthトークンを保持
return d.saveConfig(cfg)
}
doctorの回復パスでは以下が行われません:
api-keyにダウングレードする際の認証モードの移行をログに記録する- フォールバックする前にセキュアストレージからOAuthトークンの復元を試みる
- 永続化する前に回復した設定が実際に動作するかを検証する
OAuthトークンの永続化のギャップ
OAuthトークンはメインの設定ファイルとは別に保存され、通常はキーチェーンまたは安全な認証情報ストアに保存されます。doctorの回復中:
// doctorはauth_mode: api-keyで新しい設定を保存する
// しかし、次のようなチェックは行わない: 「キーチェーンにOAuthトークンはまだありますか?」
// もしあるなら、なぜapi-keyモードに切り替えなければならないのか?
🛠️ 解決手順
暫定的な回避策(ユーザー側)
この問題をすぐに経験している場合は、以下を実行してください:
# 1. ゲートウェイを停止
openclaw gateway stop
# 2. 破損した設定を消去
rm -f ~/.openclaw/config.yaml
# 3. ゲートウェイを再起動(新しいOAuth認証を求められます)
openclaw gateway start
# 4. 認証モードがoauthに設定されていることを確認
openclaw config get auth.mode
# 期待される出力: oauth
恒久的な修正(コード変更が必要)
修正1: 認証モードの移行ログを追加
config/doctor.goで認証モード変更のログを追加:
// 修正後(修正された動作)
func (d *Doctor) repairConfig() error {
cfg, err := d.loadConfig()
previousAuthMode := ""
if err == nil {
previousAuthMode = cfg.Auth.Mode
}
if err != nil {
cfg = &Config{}
}
// ... 修復ロジック ...
// 認証モードが変更された場合はログを記録
if previousAuthMode != "" && cfg.Auth.Mode != previousAuthMode {
log.Info("[auth] mode transition detected",
"from", previousAuthMode,
"to", cfg.Auth.Mode,
"reason", "config_repair")
}
return d.saveConfig(cfg)
}
修正2: フォールバック前にOAuthトークンの復元を試行
// 修正後(修正された動作)
func (d *Doctor) attemptOAuthRecovery() (bool, error) {
// セキュアストレージにOAuthトークンがあるかをチェック
tokens, err := keychain.GetTokens("openclaw-oauth")
if err != nil || tokens == nil {
return false, nil // OAuthトークンが利用不可
}
// トークンが存在 - api-keyにフォールバックする代わりにOAuthモードを復元
cfg := &Config{
Auth: AuthConfig{
Mode: "oauth",
Provider: "openai",
},
OAuth: OAuthConfig{
AccessToken: tokens.AccessToken,
RefreshToken: tokens.RefreshToken,
ExpiresAt: tokens.ExpiresAt,
},
}
log.Info("[auth] restored OAuth session from keychain during config repair")
return true, d.saveConfig(cfg)
}
修正3: 設定検証ガードを追加
gateway/main.goの起動シーケンスで:
// 修正後(修正された動作)
func startGateway() error {
// 他的一切よりも先に設定を読み込み検証
cfg, err := config.Load()
if err != nil {
return fmt.Errorf("config load failed: %w", err)
}
if err := cfg.Validate(); err != nil {
// doctorをサイレントに実行しない - 停止してユーザーに通知
return fmt.Errorf("config validation failed: %w. Run 'openclaw doctor --fix' to repair.", err)
}
// ... 起動の続き ...
}
🧪 検証
修正の確認
コード変更を適用した後、以下の手順で修正を確認します:
# 1. doctorの回復をテストするために意図的に設定ファイル破損させる
echo "invalid: [yaml" > ~/.openclaw/config.yaml
# 2. ゲートウェイを起動
openclaw gateway start
# 3. 認証モードの移行についてログを確認
grep -A5 "auth.*mode transition" ~/.openclaw/logs/gateway.log
# 期待される出力:
# INFO [auth] mode transition detected from=oauth to=api-key reason=config_repair
OAuth復元の動作確認
# 1. 設定を消去
rm -f ~/.openclaw/config.yaml
# 2. キーチェーンにOAuthトークンを手動で設定(既存のセッションをシミュレート)
openclaw auth store --provider openai --oauth-access-token "test_token" --oauth-refresh-token "refresh_test"
# 3. 破損した設定でゲートウェイを起動
echo "invalid: yaml" > ~/.openclaw/config.yaml
openclaw gateway start
# 4. api-keyにフォールバックする代わりにOAuthモードが復元されたことを確認
openclaw config get auth.mode
# 期待される出力: oauth
# 5. 復元ログを確認
grep "restored OAuth session" ~/.openclaw/logs/gateway.log
# 期待される出力:
# INFO [auth] restored OAuth session from keychain during config repair
リグレッションテストチェックリスト
- クリーンスタート: 新規OAuth認証で有効な設定が作成される
- 設定の破損: DoctorがOAuthモードを失うことなく設定を修復する
- ログの完全性: すべての認証モード変更が理由とともにログに記録される
- キーチェーンの永続性: OAuthトークンが設定の破損に耐える
- 起動時の検証: 無効な設定に対して明確なエラーでゲートウェイが即座に失敗する
⚠️ よくある落とし穴
環境固有のトラップ
macOS (darwin)
- キーチェーンのアクセス許可: OpenClawがHomebrewでインストールされた場合、キーチェーンへのアクセス許可がない可能性があります。
システム設定 > セキュリティとプライバシー > プライバシー > キーチェーンアクセスから許可を与えてください。 - ファイルの調整: macOSは設定ファイルの読み取りをキャッシュする可能性があります。ファイル調整が古い読み取りを引き起こしている場合は
csrutilチェックを使用してください。 - パスの展開: 設定パス内のチルダ(
~)は某些コンテキストで正しく展開されない場合があります。常に$HOMEまたは絶対パスを使用してください。
Docker/コンテナ環境
- ボリュームのアクセス許可: 設定がホストからマウントされている場合、UID/GIDの互換性を確認してください。OpenClawはデフォルトでUID 1000として実行されます。
- キーチェーンが利用不可: Dockerコンテナはホストのキーチェーンにアクセスできません。OAuthトークンは環境変数またはDocker互換のシークレットストア経由で渡す必要があります。
- 設定のオーバーレイ: 複数の
-v ~/.openclaw:/app/.openclawマウントが競合状態を引き起こす可能性があります。単一のボリュームマウントポイントを使用してください。
Windows
- パス区切り文字: Windowsでは設定パスにバックスラッシュを使用します。PowerShellでは予期せずエスケープされる場合があります。
- 資格情報マネージャー: Windowsはキーチェーンの代わりに資格情報マネージャーAPIを使用します。OpenClawが
資格情報の管理にアクセスできることを確認してください。 - WSL2ファイルシステム: WSL2でWindowsでマウントされたボリューム(
/mnt/c)に対してOpenClawを実行している場合、ファイルロックが予期しない動作をする可能性があります。
ユーザーの設定ミス
- YAML構文エラー: よくある間違い:
- インデントにタブを使用する
- キーの後にコロンが欠落している
- 特殊文字を含む文字列が引用符で囲まれていない
- 認証モードの不一致: OAuth認証情報を提供せずに
auth.mode: oauthを設定すると、トークンの更新後に即座に失敗します。 - 古いトークンキャッシュ: パスワードの変更やアクセスの取り消し後、キャッシュされたOAuthトークンは無効になります。
openclaw auth loginで再認証する必要があります。 - 複数の設定ファイル: OpenClawは複数の場所(
./openclaw.yaml、~/.openclaw/config.yaml、/etc/openclaw/config.yaml)から読み取ります。競合する設定によりサイレントな障害が発生する可能性があります。
開発固有の問題
- モックモードの混乱: 開発中、
OPENCLAW_MOCK_AUTH=1環境変数が実際の認証をバイパスします。本番環境ではこれが設定されていないことを確認してください。 - テストフィクスチャ: 統合テストが
~/.openclaw/test-config.yamlに書き込む場合、テストがクリーンアップに失敗すると本番設定を上書きする可能性があります。
🔗 関連するエラー
直接的に関連するエラー
Config invalid; doctor will run with best-effort config.
障害の連鎖を開始した警告。設定の検証に失敗し、自动修復がトリガーされたことを示します。これは、即座に対処すべき主な症状です。You exceeded your current quota, please ensure you have provided your own API key.(エラー429:insufficient_quota)
ゲートウェイが無効/枯渇した認証情報を持つAPIキーモードで動作していたことを確認するOpenAI APIの応答。Your credit balance is too low
フォールバックモデルにも有効なクレジットがなかったことを示すAnthropic APIの応答で、システム全体の認証障害を確認しています。authentication_required
有効な認証方法が設定されていないことをゲートウェイが検出したときの内部エラーコード。
歴史的に関連する問題
- Issue #1247: 「ゲートウェイ再起動後にOAuthトークンが永続化されない」— トークンはメモリにのみ保存され、再起動時に失われます。(v2025.8.2で修正)
- Issue #1156: 「Doctorの回復が間違ったデフォルト認証モードで設定を作成」— デフォルトが
oauthではなくnoneに設定されていました。(v2025.11.0で修正) - Issue #1089: 「認証モードの変更に対するログがない」— すべての認証の移行に対してログを追加するリクエスト。(v2025.9.5で修正されましたが、リファクタリング中にdoctorの回復パスからログ記録が削除されました)
- Issue #2201: 「Config doctorはキーチェーンからOAuthトークンを保持すべき」— この正確なバグ報告を促した機能リクエスト。
エラーコードリファレンス
1001 CONFIG_INVALID - 設定が検証に失敗しました
1002 CONFIG_WRITE_FAILED - 設定変更を永続化できません
1003 AUTH_MODE_UNSUPPORTED - 要求された認証モードが利用できません
1004 AUTH_TOKEN_EXPIRED - OAuth/アクセストークンが期限切れです
1005 AUTH_TOKEN_INVALID - トークンの署名検証に失敗しました
1006 AUTH_REFRESH_FAILED - OAuthトークンの更新がエラーを返しました
1007 QUOTA_EXCEEDED - API quotaが枯渇しました(いずれのプロバイダー)
1008 CREDENTIAL_MISSING - ストアに必要な認証情報が見つかりません