connexion icon indicating copy to clipboard operation
connexion copied to clipboard

Swagger UI Infinite Recursion Issue in 3.2.0

Open Parthib opened this issue 1 year ago • 3 comments

We recently upgraded to the latest version of Connexion due to the python_multipart package issue.

connexion[swagger-ui]==3.1.0
connexion[flask]==3.1.0

to

connexion[swagger-ui]==3.2.0
connexion[flask]==3.2.0

Everything seemed to be working fine, but we can't access our Swagger UI page anymore. If we attempt to, we get a 500, and the logs show this:

INFO:     127.0.0.1:62383 - "GET /v1/ui/swagger-ui-config.json HTTP/1.1" 200 OK
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/starlette/routing.py", line 73, in app
    response = await f(request)
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/connexion/middleware/swagger_ui.py", line 110, in _get_openapi_json
    content=jsonifier.dumps(self._spec_for_prefix(request)),
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/connexion/middleware/swagger_ui.py", line 73, in _spec_for_prefix
    return self.specification.with_base_path(base_path).raw
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/connexion/spec.py", line 221, in with_base_path
    new_spec = self.clone()
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/connexion/spec.py", line 207, in clone
    return type(self)(copy.deepcopy(self._spec))
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/connexion/spec.py", line 82, in __init__
    self._validate_spec(raw_spec)
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/connexion/spec.py", line 96, in _validate_spec
    validator.validate(spec)
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 450, in validate
    for error in self.iter_errors(*args, **kwargs):
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 384, in iter_errors
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/connexion/spec.py", line 46, in validate_defaults
    for error in validate_properties(validator, properties, instance, schema):
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_keywords.py", line 296, in properties
    yield from validator.descend(
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_keywords.py", line 275, in ref
    yield from validator._validate_reference(ref=ref, instance=instance)
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/connexion/spec.py", line 46, in validate_defaults
    for error in validate_properties(validator, properties, instance, schema):
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_keywords.py", line 296, in properties
    yield from validator.descend(
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_keywords.py", line 23, in patternProperties
    yield from validator.descend(
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_keywords.py", line 355, in oneOf
    errs = list(validator.descend(instance, subschema, schema_path=index))
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_keywords.py", line 275, in ref
    yield from validator._validate_reference(ref=ref, instance=instance)
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/connexion/spec.py", line 46, in validate_defaults
    for error in validate_properties(validator, properties, instance, schema):
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_keywords.py", line 296, in properties
    yield from validator.descend(
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_legacy_keywords.py", line 98, in items_draft3_draft4
    yield from validator.descend(item, items, path=index)
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_keywords.py", line 355, in oneOf
    errs = list(validator.descend(instance, subschema, schema_path=index))
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_keywords.py", line 275, in ref
    yield from validator._validate_reference(ref=ref, instance=instance)
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/connexion/spec.py", line 46, in validate_defaults
    for error in validate_properties(validator, properties, instance, schema):
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_keywords.py", line 296, in properties
    yield from validator.descend(
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_legacy_keywords.py", line 98, in items_draft3_draft4
...
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_types.py", line 116, in is_type
    return fn(self, instance)
  File "/Users/parthib/miniconda3/envs/backend/lib/python3.9/site-packages/jsonschema/_types.py", line 53, in is_string
    return isinstance(instance, str)
[2025-01-16 15:47:20,235] INFO [Request ID: 8d0863b0-267a-44ee-bd64-cd64381cf2a1] in errors: maximum recursion depth exceeded while calling a Python object

Any ideas for the cause of the regression?

Parthib avatar Jan 16 '25 23:01 Parthib

Same here, initially we thought there was an update with the openapi schema but didn't find anything suggesting that. We did find however that there was a change around jsonschema: https://github.com/spec-first/connexion/pull/1974.

Fixed our version to 3.1 until this is resolved

Shiakaron avatar Jan 17 '25 14:01 Shiakaron

Looked a bit closer and found that one of my recursive schemas is the source of the infinite recursion during the json validation. Here's an idea of what the schema looks like:

Step:
  oneOf:
    - $ref: "#/components/schemas/Step1"
    - $ref: "#/components/schemas/Step2"

components:
  schemas:
    BaseStep:
      type: object
      properties:
        name:
          type: string
        type:
          type: string
          enum:
            - step_1
            - step_2
        steps:
          type: array
          items:
            $ref: "#/Step"
          description: An optional array of nested steps.
      additionalProperties: true
    Step1:
      allOf:
        - $ref: "#/components/schemas/BaseStep"
        - type: object
          properties:
            type:
              type: string
              enum:
                - step_1
    Step2:
      allOf:
        - $ref: "#/components/schemas/BaseStep"
        - type: object
          properties:
            type:
              type: string
              enum:
                - step_2

When I get a chance I'll try to figure out which part of the diff between v3.1 and 3.2 caused this problem to surface

Parthib avatar Jan 29 '25 03:01 Parthib

Alright I narrowed it down to it being just this change that caused this issue:

https://github.com/spec-first/connexion/commit/bb48fb3e3d3866977777eb4bfcb2c4f502efd4ca

merged from this PR: https://github.com/spec-first/connexion/pull/2002

When I revert that self._spec to self._raw_spec, the validations around my self-referencing json schema pass and no longer run into a stackoverflow.

I gave it a decent try to understand what's going wrong internally in connexion, but I couldn't figure it out unfortunately. I'll just be monkey-patching connexion to revert this particular change so that we can use 3.2.0. I think @RobbeSneyders should know about the regression that change has caused though

Parthib avatar Jan 31 '25 09:01 Parthib

This was fixed in PR #2089. Please reopen if there is still an issue.

Ruwann avatar Oct 23 '25 12:10 Ruwann