タイトル: ツイートできないにもかかわらずエラー内容が出力されない場合
SEOタイトル: X (Twitter) API でツイートできないがエラーが出ない問題の原因と対処
| この記事の要点 |
|
問題の概要
X (旧 Twitter) API を使ったスクリプトが「ツイートが投稿されない」「しかし例外もエラーメッセージも出ない」という症状で詰まることがあります。これは多くの場合、コード側でエラーを潰しているか、レスポンスの errors フィールドをチェックしていない ことが原因です。
原因 1: try/except でエラーを握りつぶしている
もっとも多いのが、すべての例外を pass で潰しているパターン:
# アンチパターン
import tweepy
try:
api.update_status("Hello")
except:
pass # ←何が起きたか永遠にわからない
# 正しい書き方
import logging
logging.basicConfig(level=logging.DEBUG)
try:
response = client.create_tweet(text="Hello")
print(response.data)
except tweepy.TooManyRequests as e:
print(f"レート制限: {e}")
except tweepy.Unauthorized as e:
print(f"認証エラー: {e}")
except tweepy.Forbidden as e:
print(f"権限不足: {e}")
except tweepy.TweepyException as e:
print(f"その他: {e}")
print(f"response: {e.response.text if e.response else None}")
原因 2: response.errors を見ていない
X API v2 は HTTP 200 を返しつつ errors フィールドにエラーを格納することがあります:
import tweepy
client = tweepy.Client(
consumer_key="...", consumer_secret="...",
access_token="...", access_token_secret="...",
)
response = client.create_tweet(text="Hello")
# data だけ見ているとエラーを見落とす
if response.errors:
for err in response.errors:
print(f"エラー: {err}")
# 完全なレスポンス
print(response.data)
print(response.includes)
print(response.errors)
print(response.meta)
原因 3: API v1.1 廃止 / 有料化
2023 年 4 月、X は API v1.1 のほとんどを廃止 し、有料 API tier 制に変更しました(2024 時点):
| Tier | 料金 | 主な制限 |
|---|---|---|
| Free | $0 | POST のみ。500 ツイート/月。GET 不可 |
| Basic | $100/月 | 3000 ツイート/月。GET 一部可能 |
| Pro | $5000/月 | 30 万ツイート/月。full-archive search |
| Enterprise | $42k〜/月 | 商用向け、契約ベース |
古いコードで v1.1 の statuses/update.json を叩いていれば、410 Gone または 404 で動かないはずです。すべてv2 へ移行 が必要です。
原因 4: App permissions が Read-only
Twitter Developer Portal で作った App はデフォルトが Read-only で、これだとツイート POST ができません:
- developer.twitter.com でアプリを選択
- User authentication settings → Edit
- App permissions を Read and write(または Read + write + Direct Messages)に
- Save
- 重要: 既存の Access Token を再生成 しないと新しい権限が反映されない
原因 5: レート制限(429)
HTTP 429 が返るとライブラリによっては自動で 15 分待つ / 例外を投げる / 黙って返す等挙動が違います:
# tweepy は wait_on_rate_limit=True で自動待機
client = tweepy.Client(
consumer_key="...", ...,
wait_on_rate_limit=True, # 自動待機(推奨)
)
# 自分でハンドリングするなら
try:
response = client.create_tweet(text="Hello")
except tweepy.TooManyRequests as e:
# X-Rate-Limit-Reset で次回リセット時刻が分かる
reset = int(e.response.headers.get('x-rate-limit-reset', 0))
wait = reset - int(time.time())
print(f"レート制限。{wait} 秒後にリセット")
time.sleep(wait + 1)
診断: HTTP レイヤまでログを出す
原因が見えないときは、HTTP リクエスト / レスポンスを生で出すのが確実です:
import logging
import http.client as http_client
# requests / urllib3 のデバッグログを有効化
http_client.HTTPConnection.debuglevel = 1
logging.basicConfig(level=logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True
# これで POST 内容、ヘッダ、レスポンスがすべて見える
import tweepy
client = tweepy.Client(...)
client.create_tweet(text="Hello")
PHP / TwitterOAuth でのチェック
setApiVersion('2');
$response = $connection->post('tweets', ['text' => 'Hello'], true);
// 必ず状態を確認
$httpCode = $connection->getLastHttpCode();
$body = $connection->getLastBody();
if ($httpCode !== 201) {
error_log("Tweet failed: HTTP $httpCode");
error_log("Response: " . json_encode($response));
error_log("Body: " . $body);
}
// errors フィールドのチェック
if (isset($response->errors)) {
foreach ($response->errors as $err) {
error_log("Error: " . $err->message);
}
}
典型的なエラーコード一覧
| HTTP | 意味 | 原因 |
|---|---|---|
| 401 | Unauthorized | キー / トークン誤り or 期限切れ |
| 403 | Forbidden | 権限不足 / 重複ツイート / 凍結 |
| 404 | Not Found | v1.1 endpoint を叩いた |
| 429 | Too Many Requests | レート制限 |
| 500 | Internal Server Error | X 側障害(status.twitterstat.us) |
FAQ
Q: 同じ文面を再ツイートしようとして失敗する
A: X は重複ツイートを 403 で弾きます。タイムスタンプや絵文字を末尾に付けて差別化する必要があります。
Q: 開発者ポータルにログインできない / アプリが消えた
A: 2023 年以降、未払いアカウントのアプリが停止された例があります。Developer Portal でサブスクリプション状態を確認してください。
Q: 旧ツール(IFTTT 等)が動かなくなった
A: ほぼ全部 v1.1 廃止の影響です。X が公式に発表したフリーミアム tier への移行が必要です。