Skip to content

Maximum call stack size exceeded of complicated schemas (FHIR for example) #4411

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

Closed
igrishaev opened this issue Apr 5, 2018 · 38 comments
Closed

Comments

@igrishaev
Copy link

igrishaev commented Apr 5, 2018

On large schemas, Swagger UI either fails with RangeError: Maximum call stack size exceeded error or hangs with 100% CPU usage. In my case, these were the official FHIR schemas which may be downloaded by a link: https://www.hl7.org/fhir/fhir.schema.json.zip It would be enough to unzip them and copy the fhir.schema.json folder next to your swagger spec.

Q A
Bug or feature request? A bug
Which Swagger/OpenAPI version? dunno
Which Swagger-UI version? 3.13.0-3.13.2
How did you install Swagger-UI? Either with webjars or downloaded the release zip archive.
Which browser & version? Chrome 65.0.3325.181 (64-bit), FF 57.0.4 (64-bit)
Which operating system? Mac OS 10.11.6

Demonstration API definition

{"swagger": "2.0",
 "schemes": ["http"],
 "info": {"contact": {"email": "[email protected]"},
          "title": "sdfsdfsf"},
 "paths": {"/foo": {"get": {"description": "sdfsdfsdfdsf",
                            "responses": {200: {"description": "sdfsdf",
                                                "schema": {"$ref": "./fhir.schema.json/Practitioner.schema.json"}}}
}}}}

Configuration (browser query string, constructor, config.yaml)

I didn't change enything except the url parameter: url: "/swagger/schema",

Expected Behavior

To see the schemas.

Current Behavior

Either an exception (3.13.0) or an endless 100% CPU usage (3.13.2)

Context

I figured out by crafting a small subset of definitions out of these schemas.

@heldersepu
Copy link
Contributor

Yep, that is one XXL complex definition...
I know probably not ideal but, Have you tried with everything in one file?

@heldersepu
Copy link
Contributor

@igrishaev I noticed that you do have one file that seems to bundle all the definitions,
I created one big file to test...

encountered a few issues one of them was:
"message": "object instance has properties which are not allowed by the schema: [\"oneOf\"]",

After making the corrections to the definition the UI loads fast:
http://petstore.swagger.io/?url=https://raw.githubusercontent.com/heldersepu/hs-scripts/master/swagger/4411_swagger.json

@heldersepu
Copy link
Contributor

heldersepu commented Apr 5, 2018

After playing with the 4411_swagger.json I noticed that expanding the models is a bit sluggish but it works ... but expanding the GET completely crashes the browser

image
And as you can see the Memory usage goes out of control

@igrishaev
Copy link
Author

@heldersepu yes, I managed to compose my own big schema out from those files. I excluded some of them.

@heldersepu
Copy link
Contributor

@igrishaev On that link I sent when I click on GET the memory starts climbing up until it crashes...
With yours do you get similar memory usage?

@igrishaev
Copy link
Author

@heldersepu sorry I cannot reproduce that at the moment, but I guess the result would be the same. In Chrome, the tab hangs and stops responding to any action, and my laptop becomes hot.

@shockey
Copy link
Contributor

shockey commented Apr 6, 2018

Hmm... this is either (a) making the resolver recursively loop or (b) legitimately filling up the call stack, which is 10402 frames in Chrome.

@heldersepu, we've discussed the shallow resolver concept (refDepth) before, though I don't recall where. I think it would help a lot with this particular case.

@heldersepu
Copy link
Contributor

heldersepu commented Apr 7, 2018

@shockey Yes we talked about that on the Lazy loading of the models...
but I'm not 100% sure this case is related to that, and that is because using the defaultModelExpandDepth set to 0:
http://petstore.swagger.io/?url=https://raw.githubusercontent.com/heldersepu/hs-scripts/master/swagger/4411_swagger.json&defaultModelsExpandDepth=0&defaultModelExpandDepth=0
it still crashes when we we expand the GET.

Do you know what component is causing this crash?

@shockey
Copy link
Contributor

shockey commented Apr 7, 2018

@heldersepu, I'm still led to believe it's the resolver: when the operation is expanded, everything within the operation gets resolved, all the way down, until there are no $refs left. defaultModelExpandDepth wouldn't have an effect on this behavior, since we don't currently "step through" resolving $refs as a model is expanded.

@heldersepu
Copy link
Contributor

heldersepu commented Apr 8, 2018

I just did a quick search for "$ref": "#/definitions/Element" and there are 1746 and that's my version!
Would imagine that the original FHIR has many more, any way you can contact them for an optimized version of those definitions?

Now this is not to cover for Swagger-UI, there are issues with large/complex schemas.

@webron
Copy link
Contributor

webron commented Apr 8, 2018

@shockey almost afraid to ask... but what exactly does happen if the same ref appears 1000 times within the same schema?

@heldersepu
Copy link
Contributor

heldersepu commented Apr 9, 2018

@webron Here is a test schema with 1000 refs. (spoiler alert: it expands in milliseconds)

http://petstore.swagger.io/?url=http://swagger-net-test.azurewebsites.net/api/BigSwag/1000

That schema has one model (Test1K) with 1000 properties all are ref to the Location model.
I think the problem is deeper when the schema is truly complex with many many nested objects

Update:

I tested with as many as 10K refs using the same flat structure and it get slower but no crash

@heldersepu
Copy link
Contributor

@shockey & @webron Sorry I like breaking things!

Here is a very small (~3KB) schema, only a few models (but they are nested)
http://petstore.swagger.io/?url=http://swagger-net-test.azurewebsites.net/api/NestedSwag/7
We have only 49 "$ref" in that schema but expanding the GET crashes the browser

Looks to me we have a Big O(n!) lurking somewhere...

@shockey
Copy link
Contributor

shockey commented Apr 9, 2018

@heldersepu I agree, looks like it has more to do with depth than size.

@heldersepu
Copy link
Contributor

@shockey so back to your shallow resolver concept (refDepth) ...
Just point me where to start and let's see how far I can get

@prochnowc
Copy link

prochnowc commented Apr 10, 2018

We have been also hit by this issue in version 2.2.10.

Uncaught RangeError: Maximum call stack size exceeded
at module.exports.Resolver.getRefs (swagger-ui.js:5104)

@webron
Copy link
Contributor

webron commented Apr 10, 2018

@prochnowc that's separate as it's a completely different code base. We also no longer provide support for 2.X.

@heldersepu
Copy link
Contributor

I've been questioning why do we need to fully expanded a model?
This ties back with my suggestion to lazy load the model properties #4280
The only place I see a need is in the example, but a 20 page long example is no good.

So here is my question @shockey with a shallow resolver:

  • will the user still be able to expand a complex object all the way through?
  • or will it have a hard depth max expansion?

@heldersepu
Copy link
Contributor

heldersepu commented Apr 10, 2018

Here are some scary numbers

Schema SchemaSize ExampleSize ModelSize
NestedSwag/2 1,368 10,578 262,519
NestedSwag/3 1,662 59,703 1,321,999
NestedSwag/4 1,956 332,828 6,640,079
NestedSwag/5 2,250 1,835,953 33,305,772

I was afraid to do it with a 6, Copy/Pasting the HTML was taking and awful long time

@shockey shockey added this to the April 27, 2018 milestone Apr 19, 2018
@heldersepu
Copy link
Contributor

Maybe for extremely large object (models, examples, responses, etc) we should do the same thing that GitHub does, show the user a message and call that the object is too big:

(Sorry about that, but we can’t show files that are this big right now.)

https://github.com/swagger-api/swagger-ui/blob/master/dist/swagger-ui-bundle.js

@shockey
Copy link
Contributor

shockey commented Apr 28, 2018

@heldersepu: will the user still be able to expand a complex object all the way through, or will it have a hard depth max expansion?

you'd still be able to go arbitrarily deep: the resolver takes its last output as an input to avoid redoing work, so if you were resolving 1 level at a time, you'd go one level deeper each time you called it.

@webron: @shockey almost afraid to ask... but what exactly does happen if the same ref appears 1000 times within the same schema?

We do have to iterate over each occurrence of the $ref to replace it, but we do avoid needlessly iterating over the results of those operations (thanks to swagger-api/swagger-js#1209).

@heldersepu
Copy link
Contributor

@shockey I'm afraid that without a "hard depth max expansion" the UI will always have this issue ...

The expansion of a truly complex object creates a LOT of code, the browser will ultimately crash and burn, that's what I was researching on my scary numbers comment, looks like an exponential increase in size.

@heldersepu
Copy link
Contributor

heldersepu commented Apr 28, 2018

@shockey about the "avoid needlessly iterating" I think we can still do better ...

Take a look at the nested 7 example:
http://petstore.swagger.io/?url=http://swagger-net-test.azurewebsites.net/api/NestedSwag/7

The Model Test1 takes about 10 seconds to fully expand, one would think that since Test2 is a property under Test1 that expanding the Test2 model will be very fast (since it was already expanded), but it is not the case, it still take a while to expand.

@shockey
Copy link
Contributor

shockey commented May 4, 2018

The expansion of a truly complex object creates a LOT of code

This can't be really overstated: with your examples of 5 fields in each level of nesting, you end up with 5^n $ref fields to iterate over, by my math. For the 7-level definition, that's 78125 operations! 😱

about the "avoid needlessly iterating" I think we can still do better

Definitely. Since $ref resolution is depth-first, we can go as far as caching each $ref as we walk down the tree. That would take a lot of work off of the resolver, since it would only need to reach for each unique $ref's value once, after which it would just grab the already-computed data out of the cache.

--

As for this ticket, I'm going to take this out of my queue since the stack overflow is more related to performance than a flaw in the resolver. Let's keep the discussion of solutions going though 😄

@gaurav517
Copy link

A note from #4637 that was closed as duplicate of this issue, following is the specification causing this issue for me:

{"swagger":"2.0","info":{"description":"<table><tr><td><b>API Specification for Cool Application</b> [Endpoints with no version specified]<br><td><p><b>Service Owner: </b>First Last<br><b><a target=_blank href='https://mywiki/Service+catalog'>Service Link</a></b></p></td></tr></table>","title":"Cool Application API"},"host":"localhost:8080","basePath":"/","tags":[{"name":"basic-error-controller","description":"Basic Error Controller"},{"name":"find-by-ids-controller","description":"Find By Ids Controller"},{"name":"ping-controller","description":"Ping Controller"},{"name":"search-controller","description":"Search Controller"}],"paths":{"/error":{"get":{"tags":["basic-error-controller"],"summary":"error","operationId":"errorUsingGET","produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"head":{"tags":["basic-error-controller"],"summary":"error","operationId":"errorUsingHEAD","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"post":{"tags":["basic-error-controller"],"summary":"error","operationId":"errorUsingPOST","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"put":{"tags":["basic-error-controller"],"summary":"error","operationId":"errorUsingPUT","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"delete":{"tags":["basic-error-controller"],"summary":"error","operationId":"errorUsingDELETE","produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"options":{"tags":["basic-error-controller"],"summary":"error","operationId":"errorUsingOPTIONS","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"patch":{"tags":["basic-error-controller"],"summary":"error","operationId":"errorUsingPATCH","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"object","additionalProperties":{"type":"object"}}}}}},"/findAdsByIds":{"post":{"tags":["find-by-ids-controller"],"summary":"findAdsByIds","operationId":"findAdsByIdsUsingPOST","consumes":["application/json"],"produces":["*/*"],"parameters":[{"in":"body","name":"ids","description":"ids","required":true,"schema":{"type":"array","items":{"type":"integer","format":"int64"}}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/FindAdsByIdsResponse"}}}}},"/ping":{"get":{"tags":["ping-controller"],"summary":"ping","operationId":"pingUsingGET","produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}}}},"head":{"tags":["ping-controller"],"summary":"ping","operationId":"pingUsingHEAD","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}}}},"post":{"tags":["ping-controller"],"summary":"ping","operationId":"pingUsingPOST","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}}}},"put":{"tags":["ping-controller"],"summary":"ping","operationId":"pingUsingPUT","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}}}},"delete":{"tags":["ping-controller"],"summary":"ping","operationId":"pingUsingDELETE","produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}}}},"options":{"tags":["ping-controller"],"summary":"ping","operationId":"pingUsingOPTIONS","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}}}},"patch":{"tags":["ping-controller"],"summary":"ping","operationId":"pingUsingPATCH","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}}}}},"/postersOtherAdsSearch":{"post":{"tags":["search-controller"],"summary":"postersOtherAdsSearch","operationId":"postersOtherAdsSearchUsingPOST","consumes":["application/json"],"produces":["*/*"],"parameters":[{"in":"body","name":"request","description":"request","required":true,"schema":{"$ref":"#/definitions/SearchRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/SearchResponse"}}}}},"/randomSampleSearch":{"post":{"tags":["search-controller"],"summary":"randomSearch","operationId":"randomSearchUsingPOST","consumes":["application/json"],"produces":["*/*"],"parameters":[{"in":"body","name":"request","description":"request","required":true,"schema":{"$ref":"#/definitions/SearchRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/SearchResponse"}}}}},"/search":{"post":{"tags":["search-controller"],"summary":"search","operationId":"searchUsingPOST","consumes":["application/json"],"produces":["*/*"],"parameters":[{"in":"body","name":"request","description":"request","required":true,"schema":{"$ref":"#/definitions/SearchRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/SearchResponse"}}}}}},"definitions":{"AdData":{"type":"object","properties":{"activationDate":{"type":"string","format":"date-time"},"adFeatureData":{"$ref":"#/definitions/AdFeatureData"},"adLocationData":{"$ref":"#/definitions/AdLocationData"},"adPosterData":{"$ref":"#/definitions/AdPosterData"},"adPriceData":{"$ref":"#/definitions/AdPriceData"},"adState":{"type":"string","enum":["CREATED","MAILED","PAYABLE","PENDING","BLOCKED","DELAYED","ACTIVE","DELETED","EXPIRED"]},"adStateLifecycle":{"type":"string","enum":["CREATED__USER_CREATED","CREATED__PARTNER_CREATED","PAYABLE__WORKFLOW","ACTIVE__PARTNER_CONFIRMED","ACTIVE__TNS_SCORE_FILTER","ACTIVE__ADMIN_REVIEWED","ACTIVE__DELAYED_TIMEOUT","ACTIVE__USER_REPOSTED","MAILED__WORKFLOW","PENDING__USER_CONFIRMED","PENDING__ADMIN_CONFIRMED","PENDING__USER_UPDATED","PENDING__PARTNER_CONFIRMED","PENDING__PARTNER_UPDATED","BLOCKED__TNS_SCORE_FILTER","BLOCKED__TNS_BLOCK_FILTER","BLOCKED__ADMIN_CONFIRMED","DELAYED__TNS_SCORE_FILTER","DELAYED__FIRST_TIME_LISTER","DELETED__PARTNER_DELETED","DELETED__CONFIRMATION_TIMEDOUT","DELETED__USER_DELETED","DELETED__ADMIN_DELETED","EXPIRED__WORKFLOW_EXPIRED"]},"adType":{"type":"string","enum":["OFFER","WANTED"]},"advertisedBy":{"type":"string","enum":["AGENCY","PRIVATE"]},"attributeMap":{"type":"object","additionalProperties":{"type":"string"}},"categoryId":{"type":"integer","format":"int64"},"countryCode":{"type":"string"},"creationDate":{"type":"string","format":"date-time"},"deletionDate":{"type":"string","format":"date-time"},"description":{"type":"string"},"endDate":{"type":"string","format":"date-time"},"externalAdSourceData":{"$ref":"#/definitions/ExternalAdSourceData"},"id":{"type":"integer","format":"int64"},"images":{"type":"string"},"jobType":{"type":"string","enum":["CASUAL","TEMP","CONTRACT","PARTTIME","FULLTIME","GRADUATE","INTERNSHIP","VOLUNTEER"]},"languageCode":{"type":"string"},"lastUserEditDate":{"type":"string","format":"date-time"},"locale":{"$ref":"#/definitions/Locale"},"maximumSalary":{"type":"string"},"minimumSalary":{"type":"string"},"modificationDate":{"type":"string","format":"date-time"},"paused":{"type":"boolean"},"permanentUrlId":{"type":"integer","format":"int64"},"professionalSellerUserData":{"$ref":"#/definitions/ProfessionalSellerUserData"},"salaryType":{"type":"string","enum":["HOURLYRATE","ANNUALSALARYPACKAGE","ANNUALSALARYCOMMISSION","COMMISSIONONLY","UNPAID"]},"searchableMetaData":{"type":"string"},"sortingDate":{"type":"string","format":"date-time"},"title":{"type":"string"},"uuid":{"type":"string"},"version":{"type":"integer","format":"int64"}},"title":"AdData"},"AdFeatureData":{"type":"object","properties":{"b2cFeaturePack1":{"type":"boolean"},"b2cFeaturePack2":{"type":"boolean"},"b2cFeaturePack3":{"type":"boolean"},"bumpUp":{"type":"boolean"},"c2cFeaturePack1":{"type":"boolean"},"c2cFeaturePack2":{"type":"boolean"},"c2cFeaturePack3":{"type":"boolean"},"dealAd":{"type":"boolean"},"gpHpGallery":{"type":"boolean"},"gpTopAd":{"type":"boolean"},"gpTopAdStartDate":{"type":"string","format":"date-time"},"highlight":{"type":"boolean"},"hpGallery":{"type":"boolean"},"premiumAd":{"type":"boolean"},"priceDrop":{"type":"boolean"},"recurringBumpUp":{"type":"boolean"},"recurringBumpUpFrequency":{"type":"integer","format":"int32"},"superPremiumAd":{"type":"boolean"},"topAd":{"type":"boolean"},"topAdStartDate":{"type":"string","format":"date-time"},"urgent":{"type":"boolean"}},"title":"AdFeatureData"},"AdLocationData":{"type":"object","properties":{"confidenceLevel":{"type":"string","enum":["USE_LOCATON_TREE","OK","SERVICE_DOWN","INVALID"]},"houseNumber":{"type":"string"},"latitude":{"type":"number","format":"double"},"localityName":{"type":"string"},"locationId":{"type":"integer","format":"int64"},"locationPath":{"type":"string"},"longitude":{"type":"number","format":"double"},"mapAddress":{"type":"string"},"postCode":{"type":"string"},"showLocationOnMap":{"type":"boolean"},"streetName":{"type":"string"}},"title":"AdLocationData"},"AdPosterData":{"type":"object","properties":{"email":{"type":"string"},"facebookId":{"type":"integer","format":"int64"},"imprint":{"type":"string"},"ipAddress":{"type":"string"},"machineId":{"type":"string"},"name":{"type":"string"},"phoneNumber":{"type":"string"},"posterType":{"type":"string","enum":["PRIVATE","COMMERCIAL"]},"userId":{"type":"integer","format":"int64"}},"title":"AdPosterData"},"AdPriceData":{"type":"object","properties":{"amount":{"type":"number"},"currency":{"type":"string"},"type":{"type":"string","enum":["FIXED","NEGOTIABLE","GIVE_AWAY","SWAP_TRADE","DRIVE_AWAY"]}},"title":"AdPriceData"},"Aggregation":{"type":"object","properties":{"aggregationName":{"type":"string"},"count":{"type":"integer","format":"int64"},"metricsAggregations":{"type":"array","items":{"$ref":"#/definitions/NumericMetricsAggregation"}},"topHits":{"$ref":"#/definitions/TopHits"}},"title":"Aggregation"},"Bucket":{"type":"object","properties":{"count":{"type":"integer","format":"int64"},"key":{"type":"string"},"metricsMap":{"type":"object"},"topAds":{"type":"array","items":{"type":"string"}}},"title":"Bucket"},"BytesReference":{"type":"object","title":"BytesReference"},"Character":{"type":"object","title":"Character"},"ComparableRange«int»":{"type":"object","properties":{"max":{"type":"integer","format":"int32"},"min":{"type":"integer","format":"int32"}},"title":"ComparableRange«int»"},"ComparableRange«object»":{"type":"object","properties":{"max":{"type":"object"},"min":{"type":"object"}},"title":"ComparableRange«object»"},"Explanation":{"type":"object","properties":{"description":{"type":"string"},"details":{"type":"array","items":{"$ref":"#/definitions/Explanation"}},"match":{"type":"boolean"},"value":{"type":"number","format":"float"}},"title":"Explanation"},"ExternalAdSourceData":{"type":"object","properties":{"creationDate":{"type":"string","format":"date-time"},"lastModifiedDate":{"type":"string","format":"date-time"},"sourceAdId":{"type":"string"},"sourceExtraInfo":{"type":"string"},"sourceId":{"type":"integer","format":"int64"}},"title":"ExternalAdSourceData"},"FindAdsByIdsResponse":{"type":"object","properties":{"found":{"type":"object","additionalProperties":{"$ref":"#/definitions/AdData"}},"notFound":{"type":"array","items":{"type":"string"}}},"title":"FindAdsByIdsResponse"},"HighlightField":{"type":"object","properties":{"fragments":{"type":"array","items":{"$ref":"#/definitions/Text"}},"name":{"type":"string"}},"title":"HighlightField"},"Locale":{"type":"object","properties":{"country":{"type":"string"},"displayCountry":{"type":"string"},"displayLanguage":{"type":"string"},"displayName":{"type":"string"},"displayScript":{"type":"string"},"displayVariant":{"type":"string"},"extensionKeys":{"type":"array","items":{"$ref":"#/definitions/Character"}},"iso3Country":{"type":"string"},"iso3Language":{"type":"string"},"language":{"type":"string"},"script":{"type":"string"},"unicodeLocaleAttributes":{"type":"array","items":{"type":"string"}},"unicodeLocaleKeys":{"type":"array","items":{"type":"string"}},"variant":{"type":"string"}},"title":"Locale"},"Location":{"type":"object","properties":{"geohashPrecision":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int64"},"latitude":{"type":"number","format":"double"},"leaf":{"type":"boolean"},"locationPathLevel":{"type":"integer","format":"int32"},"longitude":{"type":"number","format":"double"},"maxLatitude":{"type":"number","format":"double"},"maxLongitude":{"type":"number","format":"double"},"minLatitude":{"type":"number","format":"double"},"minLongitude":{"type":"number","format":"double"},"radius":{"type":"number","format":"double"},"root":{"type":"boolean"}},"title":"Location"},"Map«string,Aggregation»":{"type":"object","title":"Map«string,Aggregation»","additionalProperties":{"$ref":"#/definitions/Aggregation"}},"ModelAndView":{"type":"object","properties":{"empty":{"type":"boolean"},"model":{"type":"object"},"modelMap":{"type":"object","additionalProperties":{"type":"object"}},"reference":{"type":"boolean"},"status":{"type":"string","enum":["100","101","102","103","200","201","202","203","204","205","206","207","208","226","300","301","302","303","304","305","307","308","400","401","402","403","404","405","406","407","408","409","410","411","412","413","414","415","416","417","418","419","420","421","422","423","424","426","428","429","431","451","500","501","502","503","504","505","506","507","508","509","510","511"]},"view":{"$ref":"#/definitions/View"},"viewName":{"type":"string"}},"title":"ModelAndView"},"NestedIdentity":{"type":"object","properties":{"child":{"$ref":"#/definitions/NestedIdentity"},"field":{"$ref":"#/definitions/Text"},"offset":{"type":"integer","format":"int32"}},"title":"NestedIdentity"},"NumericMetricsAggregation":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"number","format":"double"}},"title":"NumericMetricsAggregation"},"ProfessionalSellerUserData":{"type":"object","properties":{"externalId":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"}},"title":"ProfessionalSellerUserData"},"SearchHit":{"type":"object","properties":{"explanation":{"$ref":"#/definitions/Explanation"},"fields":{"type":"object","additionalProperties":{"$ref":"#/definitions/SearchHitField"}},"highlightFields":{"type":"object","additionalProperties":{"$ref":"#/definitions/HighlightField"}},"id":{"type":"string"},"index":{"type":"string"},"innerHits":{"type":"object","additionalProperties":{"$ref":"#/definitions/SearchHits"}},"matchedQueries":{"type":"array","items":{"type":"string"}},"nestedIdentity":{"$ref":"#/definitions/NestedIdentity"},"score":{"type":"number","format":"float"},"shard":{"$ref":"#/definitions/SearchShardTarget"},"sortValues":{"type":"array","items":{"type":"object"}},"source":{"type":"object"},"sourceAsString":{"type":"string"},"sourceEmpty":{"type":"boolean"},"sourceRef":{"$ref":"#/definitions/BytesReference"},"type":{"type":"string"},"version":{"type":"integer","format":"int64"}},"title":"SearchHit"},"SearchHitField":{"type":"object","properties":{"metadataField":{"type":"boolean"},"name":{"type":"string"},"value":{"type":"object"},"values":{"type":"array","items":{"type":"object"}}},"title":"SearchHitField"},"SearchHits":{"type":"object","properties":{"hits":{"type":"array","items":{"$ref":"#/definitions/SearchHit"}},"maxScore":{"type":"number","format":"float"},"totalHits":{"type":"integer","format":"int64"}},"title":"SearchHits"},"SearchRequest":{"type":"object","properties":{"adNumberFrom":{"type":"integer","format":"int32"},"aggregationFieldList":{"type":"array","items":{"type":"string"}},"attributeRangeAggregationsList":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/definitions/ComparableRange«int»"}}},"autosCategory":{"type":"boolean"},"autosTopAdsBackfillEnabled":{"type":"boolean"},"excludeIdList":{"type":"object","additionalProperties":{"type":"array","items":{"type":"integer","format":"int64"}}},"filterRangeMap":{"type":"object","additionalProperties":{"$ref":"#/definitions/ComparableRange«object»"}},"idList":{"type":"object","additionalProperties":{"type":"array","items":{"type":"integer","format":"int64"}}},"includeAggregations":{"type":"boolean"},"jobsCategory":{"type":"boolean"},"keyword":{"type":"string"},"location":{"$ref":"#/definitions/Location"},"searchByAttributesEnabled":{"type":"boolean"},"size":{"type":"integer","format":"int32"},"sortBy":{"type":"string"},"termFieldMap":{"type":"object"},"topHitsRequired":{"type":"boolean"}},"title":"SearchRequest"},"SearchResponse":{"type":"object","properties":{"adAdvertisedByCountMap":{"type":"object","additionalProperties":{"$ref":"#/definitions/Aggregation"}},"adJobTypesCountMap":{"type":"object","additionalProperties":{"$ref":"#/definitions/Aggregation"}},"adMaximumSalaryCountMap":{"type":"object","additionalProperties":{"$ref":"#/definitions/Aggregation"}},"adMinimumSalaryCountMap":{"type":"object","additionalProperties":{"$ref":"#/definitions/Aggregation"}},"adPriceTypesCountMap":{"type":"object","additionalProperties":{"$ref":"#/definitions/Aggregation"}},"adSalaryTypesCountMap":{"type":"object","additionalProperties":{"$ref":"#/definitions/Aggregation"}},"adTypesCountMap":{"type":"object","additionalProperties":{"$ref":"#/definitions/Aggregation"}},"ads":{"type":"array","items":{"$ref":"#/definitions/AdData"}},"adsPerCategoryMap":{"type":"object","additionalProperties":{"$ref":"#/definitions/Aggregation"}},"categoryAttributeCountMap":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"$ref":"#/definitions/Aggregation"}}},"featuresCountMap":{"type":"object","additionalProperties":{"$ref":"#/definitions/Aggregation"}},"geoHashBuckets":{"type":"array","items":{"$ref":"#/definitions/Bucket"}},"locationIdCountMap":{"type":"object","additionalProperties":{"$ref":"#/definitions/Aggregation"}},"size":{"type":"integer","format":"int64"}},"title":"SearchResponse"},"SearchShardTarget":{"type":"object","properties":{"index":{"type":"string"},"nodeId":{"type":"string"},"shardId":{"type":"integer","format":"int32"}},"title":"SearchShardTarget"},"Text":{"type":"object","title":"Text"},"TopHits":{"type":"object","properties":{"hits":{"$ref":"#/definitions/SearchHits"},"metaData":{"type":"object"},"name":{"type":"string"}},"title":"TopHits"},"View":{"type":"object","properties":{"contentType":{"type":"string"}},"title":"View"}}}

@bestmike007
Copy link
Contributor

How I reproduce this:

  1. Download and unzip the schema folder as the doc root
  2. Put the dist folder from the latest version (v3.17.4) of swagger ui inside it and renamed to swagger
  3. Put the demonstration api definition named 1.json inside the root folder
  4. Use serve to run a local web server
  5. Open http://127.0.0.1:5000/swagger/?url=/1.json#/default/get_foo in chrome

After failing to load several refs, the RangeError: Maximum call stack size exceeded error appears.

I set a break point here and then traced back to here. And I found the reducer which throws the error.

I saved the action payload to a global variable and tried to stringify it in order to view in a JSON viewer and it turned out to be a circular structure.

image

With further digging I found the cause: the Element model is referencing itself.

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "id": "http://hl7.org/fhir/json-schema/Element",
  "$ref": "#/definitions/Element",
  "description": "see http://hl7.org/fhir/json.html#schema for information about the FHIR Json Schemas",
  "definitions": {
    "Element": {
      "allOf": [
        {
          "description": "Base definition for all elements in a resource.",
          "properties": {
            "id": {
              "description": "unique id for the element within a resource (for internal references). This may be any string value that does not contain spaces.",
              "type": "string"
            },
            "_id": {
              "description": "Extensions for id",
              "$ref": "Element.schema.json#/definitions/Element"
            },
            "extension": {
              "description": "May be used to represent additional information that is not part of the basic definition of the element. In order to make the use of extensions safe and manageable, there is a strict set of governance  applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension.",
              "type": "array",
              "items": {
                "$ref": "Extension.schema.json#/definitions/Extension"
              }
            }
          }
        }
      ]
    }
  }
}

There's nothing wrong with the model definition, but for now swagger UI cannot handle it. Turning the cyclic json definition into an immutable map is an issue; while generating an example to view and edit is another. @shockey

@heldersepu
Copy link
Contributor

@bestmike007 thanks for the detailed report...
where is the 1.json that you used?

@bestmike007
Copy link
Contributor

It is the original demonstration API definition provided by @igrishaev

@heldersepu
Copy link
Contributor

@bestmike007 Ohh that one is huge...
Can you craft a small one from the original that reproduces the circular structure?
I thought that all circular refs issues had been resolved

@bestmike007
Copy link
Contributor

bestmike007 commented Jul 17, 2018

Yes. @heldersepu

{
  "swagger": "2.0",
  "schemes": ["http"],
  "info": {
    "contact": {
      "email": "[email protected]"
    },
    "title": "sdfsdfsf"
  },
  "paths": {
    "/foo": {
      "get": {
        "description": "sdfsdfsdfdsf",
        "responses": {
          "200": {
            "description": "sdfsdf",
            "schema": {
              "$ref": "#definitions/Element"
            }
          }
        }
      }
    }
  },
  "definitions": {
    "Element": {
      "allOf": [
        {
          "description": "Base definition for all elements in a resource.",
          "properties": {
            "id": {
              "description": "unique id for the element within a resource (for internal references). This may be any string value that does not contain spaces.",
              "type": "string"
            },
            "_id": {
              "description": "Extensions for id",
              "$ref": "Element.schema.json#/definitions/Element"
            }
          }
        }
      ]
    }
  }
}

@heldersepu
Copy link
Contributor

heldersepu commented Jul 17, 2018

@bestmike007
Is that a circular structure?

I think that here:
"$ref": "Element.schema.json#/definitions/Element"
you are referring an external file

@bestmike007
Copy link
Contributor

Sorry for that. It seems that it has to be referring an external file to reproduce the bug:

3.json

{
  "swagger": "2.0",
  "paths": {
    "/foo": {
      "get": {
        "responses": {
          "200": {
            "schema": {
              "$ref": "#definitions/Element"
            }
          }
        }
      }
    }
  },
  "definitions": {
    "Element": {
      "allOf": [
        { "$ref": "4.json#/definitions/Extension" }
      ]
    }
  }
}

4.json

{
  "definitions": {
    "Extension": {
      "allOf": [
        {
          "$ref": "3.json#/definitions/Element"
        }
      ]
    }
  }
}

You might need to kill the tab using the task manager: http://127.0.0.1:5000/swagger/?url=/3.json#/default/get_foo

heldersepu added a commit to heldersepu/hs-scripts that referenced this issue Jul 17, 2018
@heldersepu
Copy link
Contributor

heldersepu commented Jul 17, 2018

@bestmike007
Copy link
Contributor

bestmike007 commented Jul 17, 2018

Try to expand something. I'm using the latest chrome.

image

@heldersepu
Copy link
Contributor

heldersepu commented Jul 17, 2018

So that does not have anything to do with my issue in the comment: #4411 (comment)

And the schema reproducing the issue is not large or complicated...
I think we should open a new issue that clearly reflects the problem

@heldersepu
Copy link
Contributor

Latest version seems to have fixed all the issues I encountered before:

@shockey you can close this issue

@shockey shockey closed this as completed Jan 15, 2019
@shockey
Copy link
Contributor

shockey commented Jan 15, 2019

thanks as always for making my job easier, @heldersepu!

@lock lock bot locked and limited conversation to collaborators Jan 15, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants