tl;dr
PutObject
のオプションの Bucket
フィールドに空文字列を渡していませんか? 環境変数経由で設定する値がうまく渡っていない、などありませんか? もう一度点検してみましょう。
この記事はこれでおしまいです。検索しても全く情報が出てこなくてしばらく悩んでいたけど、しょうもない感じだった。以下はおまけです。
起こっていたこと
aws-sdk-goでS3にファイルをアップロードするクライアントを書いた。手元では動いたので開発環境にデプロイして動かしてみたらなんかエラーが出る。
operation error S3: PutObject, https response error StatusCode: 400, RequestID: (snip), HostID: (snip), api error MaxMessageLengthExceeded: Your request was too big.
MaxMessageLengthExceededと出ているけど、ファイルをアップロードするのになんか制限に引っかかったか? でもS3にそんなシビアな制限ないのでは?? と思って首をかしげていた。あんまり凝ったことはしてないS3クライアントの実装だし、サンプルコードと見比べても変なところはなさそうに見える。
世の中には1x1.pngという非常にいい画像ファイルがあるのでこれをアップロードしてみると、エラーメッセージが変わった。何???
operation error S3: PutObject, https response error StatusCode: 400, RequestID: (snip), HostID: (snip), api error MalformedXML: The XML you provided was not well-formed or did not validate against our published schema
この時点では全く心当たりがなくて*1、いろいろ試行錯誤してもよく分からない。情報が足りていないので、APIコールのログを吐くようにしてデプロイし直す。
解決編
手元と開発環境でのAPIコールのログが取れたので見比べる。よく見るとリクエストの発行先がおかしい。バケット名が入ってなくない??
- 手元:
/bucket-name/hoge.png?x-id=PutObject
- 開発環境:
/hoge.png?x-id=PutObject
ここまで見たところ全てが分かった。環境変数のセットを忘れてるじゃん……。
ということで、環境変数を入れて再度デプロイしたら直った。
必須の引数 (バケット名) にうっかり空文字列を渡してもAPIコール前にはエラーにならず、変なエンドポイントを叩いた結果見慣れないエラーが返ってくる、というのが難しいポイントだった。気をつけてください。APIクライアントのコンストラクタで必須な引数が空文字列だったらエラーを返す、みたいなことをするともうちょっとよかったのだろう。
*1:ここ伏線です