Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

exception in trio example: h11._util.LocalProtocolError: not in a reusable state #70

Closed
belm0 opened this issue Aug 17, 2018 · 7 comments

Comments

@belm0
Copy link
Contributor

belm0 commented Aug 17, 2018

I haven't figured out a pattern yet but it only takes a few reloads to get this exception. Seen on OS X with h11 0.7.0.

$ python3 trio-server.py
listening on http://localhost:8080
0: Got new connection
0: Server main loop waiting for request
0: Server main loop got event: Request(method=b'GET', target=b'/', headers=[(b'host', b'localhost:8080'), (b'connection', b'keep-alive'), (b'upgrade-insecure-requests', b'1'), (b'user-agent', b'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'), (b'accept', b'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'), (b'accept-encoding', b'gzip, deflate, br'), (b'accept-language', b'en-US,en;q=0.9')], http_version=b'1.1')
0: Preparing echo response
0: Sending 200 response with 792 bytes
0: trying to re-use connection
0: Server main loop waiting for request
1: Got new connection
1: Server main loop waiting for request
0: Server main loop got event: Request(method=b'GET', target=b'/favicon.ico', headers=[(b'host', b'localhost:8080'), (b'connection', b'keep-alive'), (b'user-agent', b'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'), (b'accept', b'image/webp,image/apng,image/*,*/*;q=0.8'), (b'referer', b'http://localhost:8080/'), (b'accept-encoding', b'gzip, deflate, br'), (b'accept-language', b'en-US,en;q=0.9')], http_version=b'1.1')
0: Preparing echo response
0: Sending 200 response with 760 bytes
0: trying to re-use connection
0: Server main loop waiting for request
0: Server main loop got event: Request(method=b'GET', target=b'/xx', headers=[(b'host', b'localhost:8080'), (b'connection', b'keep-alive'), (b'upgrade-insecure-requests', b'1'), (b'user-agent', b'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'), (b'accept', b'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'), (b'accept-encoding', b'gzip, deflate, br'), (b'accept-language', b'en-US,en;q=0.9')], http_version=b'1.1')
0: Preparing echo response
0: Sending 200 response with 794 bytes
0: trying to re-use connection
0: Server main loop waiting for request
0: Server main loop got event: Request(method=b'GET', target=b'/favicon.ico', headers=[(b'host', b'localhost:8080'), (b'connection', b'keep-alive'), (b'user-agent', b'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'), (b'accept', b'image/webp,image/apng,image/*,*/*;q=0.8'), (b'referer', b'http://localhost:8080/xx'), (b'accept-encoding', b'gzip, deflate, br'), (b'accept-language', b'en-US,en;q=0.9')], http_version=b'1.1')
0: Preparing echo response
0: Sending 200 response with 762 bytes
0: trying to re-use connection
0: Server main loop waiting for request
0: Server main loop got event: Request(method=b'GET', target=b'/', headers=[(b'host', b'localhost:8080'), (b'connection', b'keep-alive'), (b'upgrade-insecure-requests', b'1'), (b'user-agent', b'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'), (b'accept', b'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'), (b'accept-encoding', b'gzip, deflate, br'), (b'accept-language', b'en-US,en;q=0.9')], http_version=b'1.1')
0: Preparing echo response
0: Sending 200 response with 792 bytes
0: trying to re-use connection
0: Server main loop waiting for request
0: Server main loop got event: Request(method=b'GET', target=b'/favicon.ico', headers=[(b'host', b'localhost:8080'), (b'connection', b'keep-alive'), (b'user-agent', b'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'), (b'accept', b'image/webp,image/apng,image/*,*/*;q=0.8'), (b'referer', b'http://localhost:8080/'), (b'accept-encoding', b'gzip, deflate, br'), (b'accept-language', b'en-US,en;q=0.9')], http_version=b'1.1')
0: Preparing echo response
0: Sending 200 response with 760 bytes
0: trying to re-use connection
0: Server main loop waiting for request
1: Error during response handler:
1: trying to send error response...
1: Sending 408 response with 0 bytes
1: trying to re-use connection
1: unexpected state {CLIENT: IDLE, SERVER: DONE} -- bailing out
1: trying to send error response...
1: ...but I can't, because our state is DONE
2: Got new connection
2: Server main loop waiting for request
Traceback (most recent call last):
  File "trio-server.py", line 240, in http_serve
    wrapper.conn.start_next_cycle()
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/h11/_connection.py", line 204, in start_next_cycle
    self._cstate.start_next_cycle()
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/h11/_state.py", line 298, in start_next_cycle
    raise LocalProtocolError("not in a reusable state")
h11._util.LocalProtocolError: not in a reusable state

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_highlevel_socket.py", line 25, in _translate_socket_errors_to_stream_errors
    yield
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_highlevel_socket.py", line 141, in receive_some
    return await self.socket.recv(max_bytes)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_socket.py", line 619, in wrapper
    return await self._nonblocking_helper(fn, args, kwargs, wait_fn)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_socket.py", line 610, in _nonblocking_helper
    return fn(self._sock, *args, **kwargs)
ConnectionResetError: [Errno 54] Connection reset by peer

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "trio-server.py", line 329, in <module>
    trio.run(serve, 8080)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 1277, in run
    return result.unwrap()
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/outcome/_sync.py", line 107, in unwrap
    raise self.error
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 1387, in run_impl
    msg = task.context.run(task.coro.send, next_send)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/contextvars/__init__.py", line 38, in run
    return callable(*args, **kwargs)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 970, in init
    self.entry_queue.spawn()
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/async_generator/_util.py", line 42, in __aexit__
    await self._agen.asend(None)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/async_generator/_impl.py", line 366, in step
    return await ANextIter(self._it, start_fn, *args)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/async_generator/_impl.py", line 202, in send
    return self._invoke(self._it.send, value)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/async_generator/_impl.py", line 209, in _invoke
    result = fn(*args)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 317, in open_nursery
    await nursery._nested_child_finished(nested_child_exc)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/contextlib.py", line 99, in __exit__
    self.gen.throw(type, value, traceback)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 202, in open_cancel_scope
    yield scope
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_multierror.py", line 144, in __exit__
    raise filtered_exc
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 202, in open_cancel_scope
    yield scope
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 317, in open_nursery
    await nursery._nested_child_finished(nested_child_exc)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 428, in _nested_child_finished
    raise MultiError(self._pending_excs)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 1387, in run_impl
    msg = task.context.run(task.coro.send, next_send)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/contextvars/__init__.py", line 38, in run
    return callable(*args, **kwargs)
  File "trio-server.py", line 320, in serve
    await trio.serve_tcp(http_serve, port)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_highlevel_open_tcp_listeners.py", line 214, in serve_tcp
    task_status=task_status
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_highlevel_serve_listeners.py", line 129, in serve_listeners
    task_status.started(listeners)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/async_generator/_util.py", line 42, in __aexit__
    await self._agen.asend(None)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/async_generator/_impl.py", line 366, in step
    return await ANextIter(self._it, start_fn, *args)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/async_generator/_impl.py", line 202, in send
    return self._invoke(self._it.send, value)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/async_generator/_impl.py", line 209, in _invoke
    result = fn(*args)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 317, in open_nursery
    await nursery._nested_child_finished(nested_child_exc)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/contextlib.py", line 99, in __exit__
    self.gen.throw(type, value, traceback)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 202, in open_cancel_scope
    yield scope
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_multierror.py", line 144, in __exit__
    raise filtered_exc
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 202, in open_cancel_scope
    yield scope
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 317, in open_nursery
    await nursery._nested_child_finished(nested_child_exc)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 428, in _nested_child_finished
    raise MultiError(self._pending_excs)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_core/_run.py", line 1387, in run_impl
    msg = task.context.run(task.coro.send, next_send)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/contextvars/__init__.py", line 38, in run
    return callable(*args, **kwargs)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_highlevel_serve_listeners.py", line 27, in _run_handler
    await handler(stream)
  File "trio-server.py", line 247, in http_serve
    await wrapper.shutdown_and_clean_up()
  File "trio-server.py", line 168, in shutdown_and_clean_up
    got = await self.stream.receive_some(MAX_RECV)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_highlevel_socket.py", line 141, in receive_some
    return await self.socket.recv(max_bytes)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/contextlib.py", line 99, in __exit__
    self.gen.throw(type, value, traceback)
  File "/Users/john/.pyenv/versions/3.6.5/lib/python3.6/site-packages/trio/_highlevel_socket.py", line 34, in _translate_socket_errors_to_stream_errors
    ) from exc
trio.BrokenStreamError: socket connection broken: [Errno 54] Connection reset by peer
@njsmith
Copy link
Member

njsmith commented Aug 17, 2018

From a quick look, my guess is that this try block:

h11/examples/trio-server.py

Lines 165 to 172 in 870fb83

try:
while True:
# Attempt to read until EOF
got = await self.stream.receive_some(MAX_RECV)
if not got:
break
finally:
await self.stream.aclose()

should have an except trio.BrokenStreamError: pass clause. Does that help?

@belm0
Copy link
Contributor Author

belm0 commented Aug 17, 2018

Yes that seems to have fixed it!

Guessing you want to properly comment the code, but otherwise let me know if I should submit a PR.

@njsmith
Copy link
Member

njsmith commented Aug 17, 2018

submit a PR

Go for it :-)

@alanbchristie
Copy link

alanbchristie commented Apr 13, 2019

Hi, I guess this fix isn't in the latest pip release (0.8.1)? I'm seeing the following with that version...

asyncio ERROR # Exception in callback H11Server.recycle_or_close(<Task finishe...> result=None>)
handle: <Handle H11Server.recycle_or_close(<Task finishe...> result=None>)>
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/local/lib/python3.7/site-packages/hypercorn/asyncio/h11.py", line 103, in recycle_or_close
    self.connection.start_next_cycle()
  File "/usr/local/lib/python3.7/site-packages/h11/_connection.py", line 204, in start_next_cycle
    self._cstate.start_next_cycle()
  File "/usr/local/lib/python3.7/site-packages/h11/_state.py", line 298, in start_next_cycle
    raise LocalProtocolError("not in a reusable state")
h11._util.LocalProtocolError: not in a reusable state

Or is this a different fault?

@njsmith
Copy link
Member

njsmith commented Apr 13, 2019

@alanbchristie This issue is about a bug in the example code in the h11 docs. It's not about a bug in h11 itself. It looks like you're using hypercorn, not the example code, so it's probably a different issue.

Unless you have some specific reason to think that your issue is caused by a bug in h11, I'd start by asking in the quart chat or filing a bug on hypercorn.

@alanbchristie
Copy link

Thanks, I've done that now. Apologies for raising the question here.

@njsmith
Copy link
Member

njsmith commented Apr 15, 2019

@alanbchristie No worries! I just want to maximize your chances of getting a useful answer :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants