以下MarkdownExportのコピペママ
FastAPI でWebsocketを使っていて次のようなエラーが出た。対処は?
AttributeError: ‘WebSocketProtocol’ object has no attribute ‘transfer_data_task’. Did you mean: ‘transfer_data_exc’?
このエラーは、websockets ライブラリ側のバグ(特定条件で transfer_data_task がセットされる前に close() が呼ばれる)で、FastAPI/Starlette/uvicorn を使った WebSocket でも報告されています。^1_1
原因の概要
uvicornが内部で使っているwebsocketsの「legacy implementation」で、 クライアントが接続直後に即切断するなどのタイミング次第で、self.transfer_data_taskがまだ作られていないのにclose()内でawait self.transfer_data_taskが実行されてしまう
という状況が起きます。^1_1
- その結果として
AttributeError: 'WebSocketProtocol' object has no attribute 'transfer_data_task'が投げられます。^1_1
対処方針(実務的)
いまのところアプリ側コードで「綺麗に握りつぶす」のは難しく、
ランタイムと依存パッケージの組み合わせを更新 or 変更するのが現実解です。
優先度順に書きます。
1. uvicorn / websockets を最新安定版にする
pip list などでバージョンを確認し、次のように更新してみてください。
pip install -U uvicorn websockets
websockets の issue で同じエラーが報告されており、
今後のバージョンで修正が入る見込みがあるため、まずは最新版で再現するか確認するのが早いです。^1_2
2. uvicorn の WebSocket 実装を切り替える(可能なら)
uvicorn には websockets 以外のバックエンド実装もあり、
オプションやバージョンによっては「Sans-I/O 実装」に切り替えを検討できます。^1_2
例(あくまで概念的・環境により変わる):
uvicorn app.main:app --ws websockets # デフォルト
# → 将来的に別実装が選べる場合は --ws {impl} などで変更
--ws オプションで選べる実装や推奨設定は、使っている uvicorn のドキュメント・リリースノートを確認してください。^1_2
3. 一時的な割り切りとして
このエラーは「クライアントが過激に接続/切断を繰り返した時」(負荷テスト、激しいリロードなど)に出やすいと報告されています。^1_1
- 実運用で頻発しないなら、ログレベルを調整して「既知のライブラリバグ」として扱う。
- 「500 が返る」「プロセスが落ちる」など実害が大きい場合は、
上記 1・2 のアップデート/切替を優先的に検討する。
もし可能なら教えてほしい情報
もう少し踏み込んだ対処(バージョン固定の提案など)もできますので、以下が分かると精度が上がります。
python/fastapi/starlette/uvicorn/websocketsのバージョン- uvicorn の起動コマンド(
--wsなど) - エラーが出る条件(ブラウザのリロード連打など)
これらを教えてもらえれば、あなたの環境に即した具体的な組み合わせ案を出します。
^1_10^1_4^1_6^1_8
?
# python –version
Python 3.14.3
pip freeze
annotated-doc==0.0.4
annotated-types==0.7.0
anyio==4.12.1
arq==0.27.0
click==8.3.1
fastapi==0.128.1
gunicorn==25.0.1
h11==0.16.0
hiredis==3.3.0
idna==3.11
packaging==26.0
pydantic==2.12.5
pydantic_core==2.41.5
PyJWT==2.11.0
redis==5.3.1
starlette==0.50.0
typing-inspection==0.4.2
typing_extensions==4.15.0
uvicorn==0.40.0
watchfiles==1.1.1
websockets==16.0
この環境の uvicorn 0.40.0 + websockets 16.0 は最新で、このエラーは websockets legacy 実装の既知バグです。^2_1
推奨対処
uvicorn の --ws websockets-sansio オプションを使い、Sans-IO 実装に切り替えてください。
これで transfer_data_task 関連の内部 API 依存がなくなり、エラーが回避されます。^2_2
起動コマンド例
# 従来(デフォルト: legacy 実装でエラー発生)
uvicorn app.main:app --host 0.0.0.0 --port 8000
# 修正版(Sans-IO 実装に指定)
uvicorn app.main:app --host 0.0.0.0 --port 8000 --ws websockets-sansio
- uvicorn 0.35.0 以降(あなたの 0.40.0 でOK)で Sans-IO が追加されました。^2_1
- websockets 16.0 でも動作します。legacy API の非推奨問題を回避。^2_1
確認手順
- 上記コマンドで起動。
- エラーが再現する条件(例: クライアントの高速接続/切断)でテスト。
- ログに
WebSocketsSansIOProtocol系のメッセージが出れば成功。
なぜこれで解決するか
- legacy 実装(デフォルト):
websocketsの古い private API を使い、transfer_data_taskが未セット時のclose()でクラッシュ。^2_1 - Sans-IO 実装: Sans-I/O API(websockets 10.0+ の公式)を使い、より安定。uvicorn 開発者もこれを推奨。^2_3
追加アドバイス
- Gunicorn 併用時:
gunicorn22.0.1 以降でUvicornWorkerに--ws websockets-sansioを渡せます。
gunicorn app.main:app -k uvicorn.workers.UvicornWorker --worker-args "--ws websockets-sansio"
- 他オプション:
| オプション | 説明 |
|---|---|
--ws wsproto | wsproto ライブラリ使用(別インストール必要、pip install wsproto) |
--ws websockets | legacy(デフォルト・問題あり) |
--ws websockets-sansio | 推奨・最新安定 |
これで直らない場合、再現コードや起動コマンド全文を教えてください。^2_1
^2_10^2_5^2_7^2_9
?