X投稿の403エラーは「文字数オーバー」ではなく「重み付き文字数オーバー」だった ― 日本語投稿の文字数チェックを作り直した話

文・編集: J-WORKS編集部公開日: 更新日: 事実確認日:

J-WORKSではAIが書いたX(旧Twitter)の投稿を自動で公開している。ある時期からX投稿が403エラーで失敗するようになり、文字数チェックは通っているのに失敗する原因を調べたところ、Xが実際に使う「重み付き文字数」ではなく、プログラム上の単純な文字数で判定していたことが分かった。直近の成功1件・失敗6件を数え直して原因を確定し、投稿前のチェックを作り直した記録。

検証条件

J-WORKSでは、AIが作ったX向けの投稿文を、品質チェックに通してから自動で公開している。品質チェックには「Xの上限である280文字を超えていないか」という項目があり、ここを通過した投稿だけが公開に進む設計だった。ところが、このチェックを通過したはずの投稿が、Xへ送った時点で403エラー(「この操作は許可されていません」という意味の応答)になって公開できない、という失敗が続いていた。エラーの文面だけを見ると権限や認証の問題に見えるため、最初は文字数が原因だとは考えにくい状況だった。今回検証したのは、「チェックを通った投稿がなぜ失敗するのか」「成功した投稿と失敗した投稿の違いは何か」である。

実行内容

直近のX投稿のうち、成功した1件と失敗した6件を並べ、公開しようとした最終的な本文(本文の後ろにハッシュタグを付けたもの)を、X公式の数え方で数え直した。Xの280文字という上限は、すべての文字を1文字として数えるわけではない。英数字や一般的な記号は1文字分、日本語の漢字・ひらがな・カタカナ、全角記号、大半の絵文字は2文字分として数え、URLは長さに関係なく一律23文字分として数える。この「重み付き文字数」で数え直すと、成功した1件は221、失敗した6件は298〜379となり、成功と失敗が280を境にきれいに分かれた。一方、それまでの品質チェックは、プログラムの文字列の長さ(日本語も英数字も1文字と数える)で判定しており、しかもハッシュタグを付ける前の本文だけを見ていた。日本語が中心の投稿では、チェック上は280文字以内でも、実際の重み付き文字数では大きく上限を超えていたことになる。

直近のX投稿7件の比較(2026年9月2日の調査時点)
投稿件数それまでの文字数チェック重み付き文字数(本文+ハッシュタグ)Xへの投稿
成功した投稿1件通過221成功
失敗した投稿6件通過298〜379失敗

「それまでの文字数チェック」は、ハッシュタグを付ける前の本文を、日本語も英数字も1文字として数え、280以内かを見るものでした。7件それぞれの通常の文字数(すべて1文字として数えた値)は記録に残っていないため、表には載せていません。

重み付けのしくみ(説明用の例。実際の投稿文ではありません)
文字列の例通常の文字数重み付き文字数上限280に対して
日本語110文字+英字1文字111221(110×2+1)以内
日本語149文字149298(149×2)超過
日本語200文字200400(200×2)超過
英数字250文字250250(英数字は1文字分)以内
日本語10文字+半角スペース+URL1本URLの長さによって変わる44(10×2+1+URLは一律23)以内

数え方はX公式ドキュメントの説明(日本語などは1文字を2文字分、URLは長さに関係なく23文字分)に沿っています。例の文字列の長さは、修正時に追加した自動テストで使ったものです。

結果

原因は「上限を超えた投稿をXが受け付けなかった」ことであり、権限の設定ではなかった。品質チェックの文字数判定を、X向けに限って次のように作り直した。判定の対象を「ハッシュタグを付けた後の、実際に送る最終的な本文」に変え、数え方をX公式の重み付き文字数に変えた。簡略化した例: 「1文字ずつ見て、英数字などは1、それ以外は2を足す。URLは1本につき23を足す。合計が280以下なら合格」。さらに、品質チェックとは別に、Xへ送る直前にも同じ判定をもう一度行い、上限を超えていればXへは送らずに社内のエラーとして止めるようにした。新しい判定で、成功1件・失敗6件の計7件を数え直すと、7件すべてを正しく「通る/通らない」に分けられた。

失敗原因

原因は、文字数の上限を「何を1文字として数えるか」まで確認せずに、プログラムで一番手軽な文字数の数え方をそのまま使っていたことにある。英語中心の投稿であれば、この2つの数え方の差はほとんど出ないため気づきにくい。日本語中心の投稿では、重み付き文字数が単純な文字数のほぼ2倍になるため、チェックを通っているのに実際は上限を大きく超える、というずれが常に起きうる状態だった。加えて、ハッシュタグを付ける前の本文で判定していたため、ハッシュタグの分だけさらに実際の長さとずれていた。

改善

新しい外部ライブラリは追加せず、Xが公開している数え方の設定(どの文字の範囲を1文字分とし、それ以外を2文字分とするか、URLを何文字分とするか)に沿った、小さな計算処理を自前で用意した。公式の処理が行っている「複数の部品からなる絵文字を1文字として数える」細かい扱いは再現していないが、この省略は文字数を実際より多めに数える方向にしか働かないため、上限超えの投稿を見逃す方向の誤差にはならない。また、AIへの執筆指示にも「日本語は2文字分として数えるので、日本語中心の本文は実質140文字程度が目安」「ハッシュタグも含めて、重み付き文字数で260程度以下を目安にする」と書き添え、そもそも長すぎる投稿が作られにくいようにした。X以外の媒体の文字数チェックは変更していない。なお、この重み付けは「日本語なら2倍」と覚えるより、「どの文字の範囲が1倍か」という表で覚える方が正確である。英数字だけでなく、ギリシャ文字やキリル文字なども1倍の範囲に入る一方、全角の記号や大半の絵文字は2倍になる。投稿文に全角の括弧や記号を多く使うと、見た目の文字数以上に重み付き文字数が増える点にも注意が必要である。

現在の結論

2026年9月2日の修正で確認できたのは、成功と失敗の分かれ目が重み付き文字数の280だったこと、新しい判定で過去の7件を正しく分けられたこと、そして上限を超える投稿はXへ送る前に止まる仕組みになったことである。文字数制限は「何を1文字として数えるか」のルールが媒体ごとに違う。SNSへ自動で投稿する仕組みを作る場合は、プログラム上の文字数ではなく、その媒体が公開している数え方で、しかも実際に送る最終的な本文(ハッシュタグやURLを付けた後)で判定することをおすすめする。エラーの文面が文字数と無関係に見える場合でも、成功例と失敗例を同じ物差しで数え直すと、原因が見えることがある。同じような仕組みを作る場合の確認手順としては、(1)失敗した投稿と成功した投稿を少なくとも1件ずつ集める、(2)送ろうとした最終的な本文を、媒体の公式の数え方で数え直す、(3)成功と失敗が上限の前後で分かれるかを見る、(4)分かれれば、チェックの数え方と判定の対象を直し、送信の直前にも同じ判定を置く、の順が分かりやすい。

根拠

2026-09-02(JST)に実装したコード修正の記録(変更内容とコミットメッセージ)と、その修正で追加した自動テスト、およびJ-WORKS社内のノウハウ記録による。

参考資料