When using s3fs with aiobotocore 3.x and moto (mock_aws), any write operation raises KeyError: "local variable ''response'' is not defined" from inside s3fs.core._error_wrapper. The real underlying error is masked entirely.
I see the following traceback:
File ".../s3fs/core.py", line 214, in _error_wrapper
raise err
File ".../s3fs/core.py", line 210, in _error_wrapper
await tb.tb_frame.f_locals"response"
KeyError: "local variable ''response'' is not defined"
RuntimeWarning: coroutine 'AioAwsChunkedWrapper.read' was never awaited
with versions:
s3fs 2026.2.0
aiobotocore 3.2.0
moto 5.1.21
botocore 1.42.55
boto3 1.42.55
Python 3.13
Root cause
_error_wrapper contains this recovery block for 'coroutine'-related errors:
if "'coroutine'" in str(err):
tb = err.__traceback__
while tb.tb_next:
tb = tb.tb_next
try:
await tb.tb_frame.f_locals["response"] # <-- no guard
except Exception as e:
err = e
It unconditionally accesses tb.tb_frame.f_locals["response"]. With real aiohttp the innermost frame always contains a response local, but when moto intercepts HTTP calls the innermost frame is inside moto/s3/responses.py:_handle_encoded_body, which has no response variable. The KeyError replaces the original error.
The 'coroutine'-related error that triggers this block is caused by a separate moto bug (moto's BotocoreStubber calls body.readline() synchronously on aiobotocore 3.x's async AioAwsChunkedWrapper), but the missing guard might independently be a potential problem.
Minimal reproducer
import os, boto3, s3fs
from moto import mock_aws
os.environ["AWS_ACCESS_KEY_ID"] = "testing"
os.environ["AWS_SECRET_ACCESS_KEY"] = "testing"
os.environ["AWS_DEFAULT_REGION"] = "us-east-1"
@mock_aws
def test():
boto3.client("s3", region_name="us-east-1").create_bucket(Bucket="test-bucket")
fs = s3fs.S3FileSystem(anon=False)
with fs.open("test-bucket/hello.txt", "w") as f:
f.write("hello world")
test()
A possible fix could be:
if "'coroutine'" in str(err):
tb = err.__traceback__
while tb.tb_next:
tb = tb.tb_next
if "response" in tb.tb_frame.f_locals: # guard added
try:
await tb.tb_frame.f_locals["response"]
except Exception as e:
err = e
When using s3fs with aiobotocore 3.x and moto (
mock_aws), any write operation raisesKeyError: "local variable ''response'' is not defined"from insides3fs.core._error_wrapper. The real underlying error is masked entirely.I see the following traceback:
with versions:
s3fs 2026.2.0
aiobotocore 3.2.0
moto 5.1.21
botocore 1.42.55
boto3 1.42.55
Python 3.13
Root cause
_error_wrappercontains this recovery block for'coroutine'-related errors:It unconditionally accesses tb.tb_frame.f_locals["response"]. With real aiohttp the innermost frame always contains a response local, but when moto intercepts HTTP calls the innermost frame is inside moto/s3/responses.py:_handle_encoded_body, which has no response variable. The KeyError replaces the original error.
The 'coroutine'-related error that triggers this block is caused by a separate moto bug (moto's BotocoreStubber calls body.readline() synchronously on aiobotocore 3.x's async AioAwsChunkedWrapper), but the missing guard might independently be a potential problem.
Minimal reproducer
A possible fix could be: