← 事故一覧へ

majormonitoring-gapverifiedfirsthand

残高切れのエラーが exit 0 で返り、空振りが成功に見えた

`claude -p` を回すバッチで、APIクレジットが尽きると「Credit balance is too low」が標準出力に出て終了コード0で返り、中身のない結果が成功扱いで積み上がった。

発生日
深刻度
5/10
影響範囲
uptime, financial
タグ
#claude-code#batch#exit-code#billing#silent-failure

原因

CLIのログインが、サブスクリプションではなくAPI課金の組織を向いており、その組織のクレジットが枯渇していた。しかもCLIはこの失敗をエラー扱いにせず、正常終了の出力として返していた。

結果

claude -p が一律で失敗し、バッチの出力は終了コードだけでは成功と見分けがつかなかった。後日、同じ文言を見た運営者が別の課金窓口に入金してしまい、$5.50が効かない側に入った。

対策

/login でサブスクリプション側のアカウントを選び直して解決した。クレジット購入は不要だった。バッチでは終了コードを信じず、各出力に Credit balance is too low が含まれていないかを必ず grep する。

何が起きたか

項目ごとにLLMの判断が要る繰り返し作業を、claude -p のループで回していた。 Claude Code を非対話で1回ずつ呼び、結果を受け取って次へ進む。よくある バッチの形だ。

ある時点から、claude -p は一律で失敗していた。ところがバッチは止まらない。 失敗の文言「Credit balance is too low」は標準出力に出て、終了コードは0だった。 ループから見れば、毎回きちんと正常終了して、何かを返している。

現場の混乱

終了コードで成否を見る作りは、ここで完全に無力になった。成功も失敗も exit 0 で、どちらも標準出力に文字列を返す。違いは中身だけだ。

調べていくと、原因は残高そのものより手前にあった。CLIのログイン資格情報が、 サブスクリプションではなくAPI課金の組織を向いていた。その組織はクレジットが 枯渇しており、超過分の付与も受けられない状態だった。環境変数を外しても 直らない。保存済みのログインそのものの問題だったからだ。

話はここで終わらなかった。後日、今度はAPIキー経由の呼び出しで同じ 「Credit balance is too low」が出た。同じ文言なので同じ財布だと思い、運営者は サブスクリプション側の課金画面に$5.50を入金した。だがAPIキーの課金元は 別の窓口で、その入金ではAPIは動かない。同じ文言が、別々の財布を指していた。

原因

  • CLIのログインが、クレジットの尽きたAPI課金の組織を向いていた。
  • claude -p は残高切れをエラーとして返さず、exit 0 と標準出力で返す。 そのため「空振り」が「成功」と同じ形で記録された。
  • 「Credit balance is too low」という同じ文言が、CLI/アプリ経由とAPIキー経由の どちらでも出る。課金元が違うのに、文言からは区別できない。

対策

  • claude を起動して /login を実行し、サブスクリプション側のアカウントを 選び直した。これで解決し、クレジットの購入は要らなかった。
  • バッチでは終了コードを信じない。各出力の中身を検証し、Credit balance is too low が含まれていないかを grep するのを必須にした。
  • 残高切れの間の代替として、サブスクリプション側で動くサブエージェント (クレジット不要)に作業を回す。
  • APIキーが同じ文言を返したときは、アプリ側ではなくAPIコンソール側の残高と、 組織の切り替えが正しいかを確かめる。文言が同じでも財布は同じとは限らない。

出典

  • 運営者自身が起こした事故の一次記録です。外部に公開された元記事はありません。