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

Runtime Error: maximum recursion depth #114

Closed
gsteele13 opened this issue Sep 30, 2020 · 5 comments · Fixed by #115
Closed

Runtime Error: maximum recursion depth #114

gsteele13 opened this issue Sep 30, 2020 · 5 comments · Fixed by #115
Labels
bug Something isn't working

Comments

@gsteele13
Copy link

gsteele13 commented Sep 30, 2020

Bug description

I have a Jupyterhub configured to use Native Auth, with DockerSpawner.

After running for a while (months or weeks, a time which I suspect depends on how many users are active), the server experiences a runtime error RecursionError: maximum recursion depth exceeded while calling a Python object

Expected behaviour

I would expect that it would just run.

Actual behaviour

After some period of time, it triggers runtime errors:

Looking in the error message output, it seems that this might be related to the Native Auth authenticator:

    HTTPServerRequest(protocol='https', host='jupyterhub-steelelab.tnw.tudelft.nl', method='GET', uri='/hub/login?next=%2Fhub%2Fuser%2Flieuwelocht%2Fmetrics', version='HTTP/1.1', remote_ip='::ffff:1
45.94.145.117')
    Traceback (most recent call last):
      File "/root/miniconda3/lib/python3.7/site-packages/tornado/web.py", line 1703, in _execute
        result = await result
      File "/root/miniconda3/lib/python3.7/site-packages/jupyterhub/handlers/login.py", line 135, in get
        self.finish(self._render(username=username))
      File "/root/native_auth/nativeauthenticator/nativeauthenticator/handlers.py", line 151, in _render
        {'next': self.get_argument('next', '')},
      File "/root/miniconda3/lib/python3.7/site-packages/jupyterhub/handlers/base.py", line 1044, in render_template
        return template.render(**template_ns)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/environment.py", line 1090, in render
        self.environment.handle_exception()
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/environment.py", line 832, in handle_exception
        reraise(*rewrite_traceback_stack(source=source))
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/_compat.py", line 28, in reraise
        raise value.with_traceback(tb)
      File "/root/native_auth/nativeauthenticator/nativeauthenticator/templates/native-login.html", line 1, in top-level template code
        {% extends "page.html" %}
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/environment.py", line 592, in _generate
        optimized=self.optimized,
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 87, in generate
        generator.visit(node)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 32, in visit
        return f(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 774, in visit_Template
        self.blockvisit(node.body, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 381, in blockvisit
        self.visit(node, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 32, in visit
        return f(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 1233, in visit_Macro
        macro_frame, macro_ref = self.macro_body(node, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 580, in macro_body
        self.blockvisit(node.body, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 381, in blockvisit
        self.visit(node, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 32, in visit
        return f(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 1458, in visit_Assign
        self.visit(node.node, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 32, in visit
        return f(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 70, in new_func
        new_node = self.optimizer.visit(node, frame.eval_ctx)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 33, in visit
        return self.generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/optimizer.py", line 27, in generic_visit
        node = super(Optimizer, self).generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 67, in generic_visit
        new_node = self.visit(old_value, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 33, in visit
        return self.generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/optimizer.py", line 27, in generic_visit
        node = super(Optimizer, self).generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 67, in generic_visit
        new_node = self.visit(old_value, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 33, in visit
        return self.generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/optimizer.py", line 27, in generic_visit
        node = super(Optimizer, self).generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 67, in generic_visit
        new_node = self.visit(old_value, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 33, in visit
        return self.generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/optimizer.py", line 27, in generic_visit
        node = super(Optimizer, self).generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 67, in generic_visit
        new_node = self.visit(old_value, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 33, in visit
        return self.generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/optimizer.py", line 27, in generic_visit
        node = super(Optimizer, self).generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 66, in generic_visit
        elif isinstance(old_value, Node):
    RecursionError: maximum recursion depth exceeded while calling a Python object

In particular, I am suspicious that this may be triggered by the line:

      File "/root/native_auth/nativeauthenticator/nativeauthenticator/templates/native-login.html", line 1, in top-level template code
        {% extends "page.html" %}

After this initial error message, the logfiles are filled with tracebacks like this one:

    Traceback (most recent call last):
      File "/root/miniconda3/lib/python3.7/site-packages/tornado/web.py", line 1703, in _execute
        result = await result
      File "/root/miniconda3/lib/python3.7/site-packages/jupyterhub/handlers/login.py", line 135, in get
        self.finish(self._render(username=username))
      File "/root/native_auth/nativeauthenticator/nativeauthenticator/handlers.py", line 151, in _render
        {'next': self.get_argument('next', '')},
      File "/root/miniconda3/lib/python3.7/site-packages/jupyterhub/handlers/base.py", line 1043, in render_template
        template = self.get_template(name)
      File "/root/miniconda3/lib/python3.7/site-packages/jupyterhub/handlers/base.py", line 1037, in get_template
        return self.settings['jinja2_env'].get_template(name)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/environment.py", line 883, in get_template
        return self._load_template(name, self.make_globals(globals))
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/environment.py", line 857, in _load_template
        template = self.loader.load(self, name, globals)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/loaders.py", line 426, in load
        return loader.load(environment, name, globals)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/loaders.py", line 426, in load
        return loader.load(environment, name, globals)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/loaders.py", line 426, in load
        return loader.load(environment, name, globals)
      [Previous line repeated 982 more times]
    RecursionError: maximum recursion depth exceeded

How to reproduce

  1. Start jupyterhub server with NativeAuth
  2. Allow ~15 users to connect and run things for a few months. Or possibly by having the browser of a user call an HTTP GET about 1900 times.
  3. First recursion depth error occurs as described above, followed by the second recursion depth error as described above
  4. Server can no longer be connected to by new connects (existing connections do persist, but if I open a link to server in an incogento tab, I cannot connect).

Your personal set up

  • OS:
    Linux
  • Version:

jupyterhub version 1.0.0

  • Configuration:

Dockerspawner

@gsteele13 gsteele13 added the bug Something isn't working label Sep 30, 2020
@welcome
Copy link

welcome bot commented Sep 30, 2020

Thank you for opening your first issue in this project! Engagement like this is essential for open source projects! 🤗

If you haven't done so already, check out Jupyter's Code of Conduct. Also, please try to follow the issue template as it helps other other community members to contribute more effectively.
welcome
You can meet the other Jovyans by joining our Discourse forum. There is also an intro thread there where you can stop by and say Hi! 👋

Welcome to the Jupyter community! 🎉

@gsteele13
Copy link
Author

Server can no longer be connected to by new connects (existing connections do persist, but if I open a link to server in an incogento tab, I cannot connect).

This also makes me suspect that the problem is related to the NativeAuth module

@djangoliv
Copy link
Contributor

I also had this problem on two instances of jupyterhub with nativeauthentificator (Sometimes with few users and in less than a week).
My instance with ldap anthentificator has never encountered this problem.

@fbessou
Copy link
Contributor

fbessou commented Oct 19, 2020

It seems to be caused by the jinja env.loader being wrapped in a new loader at each render.
It happens here

fbessou added a commit to fbessou/nativeauthenticator that referenced this issue Oct 19, 2020
The env.loader was replaced by a new ChoiceLoader wrapping the previous
loader on every render. It seems that the `_loaded` attribute was here
to avoid re-registering the loader but it was set to `True` on the
handler instance and not on its class making it useless since the a
handler instance is created for each request.

Closes jupyterhub#114.
@fbessou
Copy link
Contributor

fbessou commented Oct 20, 2020

This bug can be easily reproduced by sending a lot of requests to the /hub/login page.

while true; do $JUPYTERHUB_BASE_URL/hub/login -s > /dev/null; done

It starts to crash after around 10 seconds on my machine.

fbessou added a commit to fbessou/nativeauthenticator that referenced this issue Oct 22, 2020
The env.loader was replaced by a new ChoiceLoader wrapping the previous
loader on every render. It seems that the `_loaded` attribute was here
to avoid re-registering the loader but it was set to `True` on the
handler instance and not on its class making it useless since the a
handler instance is created for each request.

Closes jupyterhub#114.
fbessou added a commit to fbessou/nativeauthenticator that referenced this issue Oct 23, 2020
The env.loader was replaced by a new ChoiceLoader wrapping the previous
loader on every render. It seems that the `_loaded` attribute was here
to avoid re-registering the loader but it was set to `True` on the
handler instance and not on its class making it useless since the a
handler instance is created for each request.

Closes jupyterhub#114.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants