connexion icon indicating copy to clipboard operation
connexion copied to clipboard

Middleware : Exception caught where it souldn't

Open LiteApplication opened this issue 8 months ago • 7 comments

I encountered this issue that was hard to track down :

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/app/.venv/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py", line 403, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/.venv/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/.venv/lib/python3.11/site-packages/connexion/apps/abstract.py", line 288, in __call__
    return await self.middleware(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/.venv/lib/python3.11/site-packages/connexion/middleware/main.py", line 501, in __call__
    self.app, self.middleware_stack = self._build_middleware_stack()
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/.venv/lib/python3.11/site-packages/connexion/middleware/main.py", line 338, in _build_middleware_stack
    app.add_api(
  File "/app/.venv/lib/python3.11/site-packages/connexion/apps/flask.py", line 149, in add_api
    self.app.register_blueprint(api.blueprint)
  File "/app/.venv/lib/python3.11/site-packages/flask/sansio/scaffold.py", line 47, in wrapper_func
    return f(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/.venv/lib/python3.11/site-packages/flask/sansio/app.py", line 595, in register_blueprint
    blueprint.register(self, options)
  File "/app/.venv/lib/python3.11/site-packages/flask/sansio/blueprints.py", line 310, in register
    raise ValueError(
ValueError: The name '/api' is already registered for a different blueprint. Use 'name=' to provide a unique name.

I think it comes down to the assignment not taking place because of an Exception raised and silently caught here (so self.middleware_stack stays None) : https://github.com/spec-first/connexion/blob/a1c53db7a74d0fbbc22913faf70bc3d1c1b08ee2/connexion/middleware/main.py#L499 And I think that the error in question can be a KeyError here (debugger won't drill further down) : https://github.com/spec-first/connexion/blob/a1c53db7a74d0fbbc22913faf70bc3d1c1b08ee2/connexion/middleware/security.py#L131

There most likely was an error in my configuration, however I filled an issue because the cause is hidden by an exception caught wrongly which causes the library to misbehave in a way that is nowhere linked to the root cause of the issue.

Here is the KeyError :

Exception has occurred: KeyError
'scheme'
  File "/home/liteapp/adh6/api_server/.venv/lib/python3.11/site-packages/connexion/middleware/security.py", line 131, in __init__
    self.add_paths()
  File "/home/liteapp/adh6/api_server/.venv/lib/python3.11/site-packages/connexion/middleware/abstract.py", line 235, in add_api
    api = self.api_cls(specification, next_app=self.app, **kwargs)
  File "/home/liteapp/adh6/api_server/.venv/lib/python3.11/site-packages/connexion/middleware/main.py", line 338, in _build_middleware_stack
    app.add_api(
  File "/home/liteapp/adh6/api_server/.venv/lib/python3.11/site-packages/connexion/middleware/main.py", line 501, in __call__
    self.app, self.middleware_stack = self._build_middleware_stack()
  File "/home/liteapp/adh6/api_server/.venv/lib/python3.11/site-packages/connexion/apps/abstract.py", line 288, in __call__
    return await self.middleware(scope, receive, send)
  File "/home/liteapp/adh6/api_server/.venv/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 29, in __call__
    return await self.app(scope, receive, send)
  File "/home/liteapp/adh6/api_server/.venv/lib/python3.11/site-packages/uvicorn/lifespan/on.py", line 86, in main
    await app(scope, self.receive, self.send)
  File "/usr/local/lib/python3.11/asyncio/events.py", line 84, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/local/lib/python3.11/asyncio/base_events.py", line 1936, in _run_once
    handle._run()
  File "/usr/local/lib/python3.11/asyncio/base_events.py", line 608, in run_forever
    self._run_once()
  File "/usr/local/lib/python3.11/asyncio/base_events.py", line 641, in run_until_complete
    self.run_forever()
  File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
  File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
  File "/home/liteapp/adh6/api_server/.venv/lib/python3.11/site-packages/uvicorn/server.py", line 67, in run
    return asyncio.run(self.serve(sockets=sockets))
  File "/home/liteapp/adh6/api_server/.venv/lib/python3.11/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
    target(sockets=sockets)
  File "/usr/local/lib/python3.11/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/lib/python3.11/multiprocessing/process.py", line 314, in _bootstrap
    self.run()
  File "/usr/local/lib/python3.11/multiprocessing/spawn.py", line 135, in _main
    return self._bootstrap(parent_sentinel)
  File "/usr/local/lib/python3.11/multiprocessing/spawn.py", line 122, in spawn_main
    exitcode = _main(fd, parent_sentinel)
  File "<string>", line 1, in <module>
KeyError: 'scheme'

(it is possible that some lines are off because it is running inside a docker environment and the debugger is outside)

Thank you for your time and contribution to the open source world 👍

LiteApplication avatar Aug 07 '25 09:08 LiteApplication

Would you please extend this issue with a small self-contained code example - I guess it has to have a configuration error of some kind - to demonstrate the exception and broken assignment? That way I can also try to step thru the debugger and reproduce your finding.

chrisinmtown avatar Aug 15 '25 19:08 chrisinmtown

It's especially important to post an openapi.yaml file. It appears from the error that your spec might define a security scheme that requires a custom security handler? That same KeyError also is reported in issue #2061 where the spec uses an "openIdConnect" security scheme. It appears to me that Connexion has a bug here, and I proposed a fix in the discussion on that issue. Please comment.

chrisinmtown avatar Aug 18 '25 17:08 chrisinmtown

It appears this bug was fixed two months ago in PR https://github.com/spec-first/connexion/pull/1940, and the fix is not yet in any public release.

chrisinmtown avatar Aug 19 '25 10:08 chrisinmtown

However I don't think this is really fixed: my similar issue persists even when installing from main, so I'm going to debug it asap...

giuliohome avatar Sep 13 '25 10:09 giuliohome

I see from my debugging print that it passing here but it swallwos and hides the exeption

    try:
        function = deep_getattr(module, attr_path)
    except AttributeError as attr_error:
        if last_import_error:
            raise last_import_error
        else:
            print("Giulio *** *** - raise AttributeError:", attr_error)
            raise
    return function
$ python app.py 
`ConnexionMiddleware.run` is optimized for development. For production, run using a dedicated ASGI server.
INFO:     Started server process [5465]
INFO:     Waiting for application startup.
Giulio *** *** - get_function_from_name - function_name: api.hello
Giulio *** *** - get_function_from_name - function_name: api.hello_options
Giulio *** *** - get_function_from_name - function_name: api.hello
Giulio *** *** - get_function_from_name - function_name: api.hello_options
Giulio *** *** - get_function_from_name - function_name: api.hello
Giulio *** *** - get_function_from_name - function_name: api.hello_options
Giulio *** *** - get_function_from_name - function_name: api.hello
Giulio *** *** - get_function_from_name - function_name: api.hello_options
Giulio *** *** - get_function_from_name - function_name: api.hello
Giulio *** *** - get_function_from_name - function_name: app.decode_token
Giulio *** *** - raise AttributeError: module 'app' has no attribute 'decode_token'
INFO:     ASGI 'lifespan' protocol appears unsupported.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

giuliohome avatar Sep 13 '25 14:09 giuliohome

@giuliohome Today I encountered similar issue. I figured out the issue, which is actually not related to latest changes of connexion for sure, I can't share the code part mine but I can share the ways I debugged my application where exactly I caught the root cause.

The steps as follows:

  • I first added the additional traceback in the connexions line code, for me it is on the file as highlighted in below image.
Image
  • I added code something like as below
except ImportError as e:
            msg = f'Cannot resolve operationId "{operation_id}"! Import error was "{str(e)}"'

            print("****************************************************************")
            print(traceback.format_exc())
-- INSERT --

I would recommend to add the traceback in line /app/.venv/lib/python3.11/site-packages/flask/sansio/blueprints.py as per the issue description to confirm either it is app issue at your end or the connexion side issue.

Murugaraju avatar Sep 17 '25 14:09 Murugaraju

Of course I know very well what to do and indeed I have already found the bug - for sure on Connexion side (and in particular due to their vers. 3) - and sent a PR fix to the maintainers (related to the detailed issue I have also opened, where I explain all the steps). Since you missed it, I paste again the PR below (and the issue is linked inside it)

https://github.com/spec-first/connexion/pull/2082

P.S. I'm afraid this repo is no longer actively supported though

giuliohome avatar Sep 17 '25 14:09 giuliohome