Avoid error logs while interrupting the spawner

Hey there,

Similar to Custom JupyterHub Error Messages, I want to show a custom error message to interrupt the spawn, which works just fine. However, throwing an error using raise to interrupt the spawning process in pre_spawn_hook results in several errors in the logs.

For example:

[D 2026-01-14 15:00:45.179 JupyterHub user:496] Creating <class 'kubespawner.spawner.KubeSpawner'> for admin:
[D 2026-01-14 15:00:45.181 JupyterHub pages:190] Triggering spawn with supplied query arguments for admin
[D 2026-01-14 15:00:45.181 JupyterHub base:1095] Initiating spawn for admin
[I 2026-01-14 15:00:45.191 JupyterHub provider:661] Creating oauth client jupyterhub-user-admin
[I 2026-01-14 15:00:45.197 JupyterHub log:192] 302 GET /hub/spawn?profile=test -> /hub/spawn-pending/admin?profile=test (admin@...) 23.83ms
[W 2026-01-14 15:00:45.204 JupyterHub custom_jupyterhub_config:321] User admin tried to spawn a restricted profile
[E 2026-01-14 15:00:45.204 JupyterHub user:1007] Unhandled error starting admin's server: HTTP 403: Forbidden
    Traceback (most recent call last):
      File "/usr/local/lib/python3.12/site-packages/jupyterhub/user.py", line 908, in spawn
        await maybe_future(spawner.run_pre_spawn_hook())
      File "custom_jupyterhub_config.py", line 585, in pre_spawn_hook
      File "custom_jupyterhub_config.py", line 324, in setup_user_profile_environment
    tornado.web.HTTPError: HTTP 403: Forbidden

[D 2026-01-14 15:00:45.205 JupyterHub user:1100] Stopping admin
[D 2026-01-14 15:00:45.209 JupyterHub user:1122] Deleting oauth client jupyterhub-user-admin
[D 2026-01-14 15:00:45.212 JupyterHub user:1125] Finished stopping admin
[E 2026-01-14 15:00:45.215 JupyterHub gen:629] Exception in Future <Task finished name='Task-133' coro=<BaseHandler.spawn_single_user.<locals>.finish_user_spawn() done, defined at /usr/local/lib/python3.12/site-packages/jupyterhub/handlers/base.py:1115> exception=HTTPError()> after timeout
    Traceback (most recent call last):
      File "/usr/local/lib/python3.12/site-packages/tornado/gen.py", line 624, in error_callback
        future.result()
      File "/usr/local/lib/python3.12/site-packages/jupyterhub/handlers/base.py", line 1122, in finish_user_spawn
        await spawn_future
      File "/usr/local/lib/python3.12/site-packages/jupyterhub/user.py", line 1021, in spawn
        raise e
      File "/usr/local/lib/python3.12/site-packages/jupyterhub/user.py", line 908, in spawn
        await maybe_future(spawner.run_pre_spawn_hook())
      File "custom_jupyterhub_config.py", line 585, in pre_spawn_hook
      File "custom_jupyterhub_config.py", line 324, in setup_user_profile_environment
    tornado.web.HTTPError: HTTP 403: Forbidden

[D 2026-01-14 15:00:45.225 JupyterHub scopes:1010] Checking access to /hub/spawn-pending/admin via scope servers!server=admin/
[E 2026-01-14 15:00:45.226 JupyterHub pages:374] Previous spawn for admin failed: HTTP 403: Forbidden
[E 2026-01-14 15:00:45.234 JupyterHub log:184] {
      "Upgrade-Insecure-Requests": "1",
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
      "Sec-Fetch-Site": "none",
      "Sec-Fetch-Mode": "navigate",
      "Sec-Fetch-User": "?1",
      "Sec-Fetch-Dest": "document",
      "Sec-Ch-Ua": "\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"",
      "Sec-Ch-Ua-Mobile": "?0",
      "Sec-Ch-Ua-Platform": "\"Windows\"",
      "Accept-Encoding": "gzip, deflate, br, zstd",
      "Accept-Language": "de-DE,de;q=0.9",
      "Cookie": "jupyterhub-hub-login=[secret]; _xsrf=[secret]; jupyterhub-session-id=[secret]",
      "Host": "...",
      "X-Forwarded-Host": "...",
      "X-Forwarded-Port": "443,80",
      "X-Forwarded-Proto": "https,http",
      "Forwarded": "for=...",
      "X-Forwarded-For": "...",
      "Connection": "keep-alive"
        

I’ve already tried to suppress the errors using some messed-up logger handler and filter combinations, but it didn’t work out for me. So, is there a way to skip the errors in the logs?

Thanks a lot.

Unfortunately, we need to fix the error handling in JupyterHub itself to handle this better. Some of the try/excepts need to account for HTTPError better.

1 Like