Repository: go-swagger/go-swagger (go)

Issue:
Generate models failed after separate swagger files, maybe caused by a self-ref property of a definition in the separated swagger file
## Problem statement

I have two swagger files: the main file(swagger.yaml, including path-item referencing swagger/business.yaml) and a separated file(swagger/business.yaml) in the subfolder. When I tried to generate models directly using swagger/business.yaml, it succeeded. But when I tried to generate models using swagger.yaml, it ran to a panic error. And it is very weird  that when I comment the last four lines in swagger/buissiness.yaml, it ran to success

## Swagger specification
[test-swagger.zip](https://github.com/go-swagger/go-swagger/files/4896092/test-swagger.zip)
swagger.yaml
```yaml
swagger: "2.0"
info:
  description: "ms api"
  version: "1.0.0"
  title: "ms api"

host: "127.0.0.1:8613"
basePath: "/rest/ms"

tags:
  - name: "business"
    description: "business info"
    externalDocs:
      description: "Find out more"
      url: "http://swagger.io"
schemes:
  - "http"

security:
  - api_key: []

paths:
  /business:
    $ref: "business.yaml#/paths/~1business"

```
swagger/business.yaml
```yaml
swagger: "2.0"
info:
  description: "Business Sub API"
  version: "1.0.0"
  title: "Business Sub-API"

host: "127.0.0.1:8080"
basePath: "/rest/ms"

tags:
  - name: "business"
    description: "business info"
    externalDocs:
      description: "Find out more"
      url: "http://swagger.io"

paths:
  /business:
    post:
      summary: Create a business
      operationId: createBusiness
      tags:
        - "business"
      parameters:
        - name: body
          in: body
          required: true
          schema:
            $ref: '#/definitions/Business'
      responses:
        200:
          description: OK
          schema:
            type: object
definitions:
  Business:
    type: object
    properties:
      children:
        type: array
        x-go-custom-tag: bson:"-"
        items:
          $ref: '#/definitions/Business'
      users:
        type: array
        x-go-custom-tag: bson:"users"
        items:
          type: object
          properties:
            role:
              type: string
              x-go-custom-tag: bson:"role"

```
> I have tried several ways to reproduce the error, such as comment the last four lines(success), change the `children` item $ref to definitions other than `#/definitions/Business`(success), remove the `children` property from Business(success), so I wonder maybe the self-ref `#/definitions/Business` is the key point, but I cant figure out the root cause.
## Steps to reproduce
1. `swagger generate model --with-flatten=expand -f swagger.yaml`
```shell
...
generator:2020/07/09 17:59:36 model.go:701: property createBusinessParamsBody["children"] (tup: false) HasValidations: true)
generator:2020/07/09 17:59:36 types.go:634: resolving schema (anon: true, req: false) 
generator:2020/07/09 17:59:36 types.go:346: resolving array (anon: true, req: false)
generator:2020/07/09 17:59:36 types.go:634: resolving schema (anon: true, req: false) 
generator:2020/07/09 17:59:36 types.go:230: resolving ref (anon: false, req: false) #/definitions/business
panic: object has no key "business"

goroutine 1 [running]:
github.com/go-openapi/spec.ResolveRef(0x189ba80, 0xc0005cf600, 0xc000de4498, 0x3, 0x3, 0xc001916080)
        /go/pkg/mod/github.com/go-openapi/spec@v0.19.8/expander.go:55 +0x350
github.com/go-swagger/go-swagger/generator.(*typeResolver).resolveSchemaRef(0xc00008ba90, 0xc000de4480, 0x1930a00, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /app/generator/types.go:235 +0x190
github.com/go-swagger/go-swagger/generator.(*typeResolver).ResolveSchema(0xc00008ba90, 0xc000de4480, 0xc001910001, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /app/generator/types.go:644 +0x1df
github.com/go-swagger/go-swagger/generator.(*typeResolver).resolveArray(0xc00008ba90, 0xc001917498, 0xc001a60001, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /app/generator/types.go:374 +0x1a3
github.com/go-swagger/go-swagger/generator.(*typeResolver).ResolveSchema(0xc00008ba90, 0xc001917498, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /app/generator/types.go:680 +0x8e3
github.com/go-swagger/go-swagger/generator.(*schemaGenContext).buildProperties(0xc001aab800, 0x4a, 0xc0019181d8)
        /app/generator/model.go:705 +0x4c3
github.com/go-swagger/go-swagger/generator.(*schemaGenContext).makeGenSchema(0xc001aab800, 0x1, 0x0)
        /app/generator/model.go:1944 +0xc96
github.com/go-swagger/go-swagger/generator.(*codeGenOpBuilder).liftExtraSchemas(0xc00191cfa8, 0xc00008b630, 0xc00008b720, 0xc000e07440, 0xc000cd4600, 0x1fdabbf, 0x18112e0, 0xc000b2e9f0)
        /app/generator/operation.go:1027 +0x1ae
github.com/go-swagger/go-swagger/generator.(*codeGenOpBuilder).buildOperationSchema(0xc00191cfa8, 0xc000d1fbb0, 0x6, 0xc000da00a0, 0x18, 0xc000da0080, 0x12, 0x192bd8c, 0x1, 0x192bd88, ...)
        /app/generator/operation.go:1092 +0x6ac
github.com/go-swagger/go-swagger/generator.(*codeGenOpBuilder).MakeBodyParameter(0xc00191cfa8, 0xc00191a9f8, 0xc00008b630, 0xc001553440, 0x0, 0x0)
        /app/generator/operation.go:773 +0x1f8
github.com/go-swagger/go-swagger/generator.(*codeGenOpBuilder).MakeParameter(0xc00191cfa8, 0x192bd8c, 0x1, 0xc00008b630, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /app/generator/operation.go:735 +0xe55
github.com/go-swagger/go-swagger/generator.(*codeGenOpBuilder).MakeOperation(0xc00191cfa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /app/generator/operation.go:325 +0x528
github.com/go-swagger/go-swagger/generator.(*appGenerator).makeCodegenApp(0xc0006a7b00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /app/generator/support.go:303 +0xfb2
github.com/go-swagger/go-swagger/generator.(*appGenerator).Generate(0xc0006a7b00, 0x0, 0x0)
        /app/generator/support.go:131 +0x7e
github.com/go-swagger/go-swagger/generator.GenerateServer(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc000441d40, 0x0, ...)
        /app/generator/support.go:40 +0xcb
github.com/go-swagger/go-swagger/cmd/swagger/commands/generate.(*Model).generate(0xc00020d7a0, 0xc000441d40, 0x0, 0x0)
        /app/cmd/swagger/commands/generate/model.go:84 +0x124
github.com/go-swagger/go-swagger/cmd/swagger/commands/generate.createSwagger(0x1ac5100, 0xc00020d7a0, 0x185ee80, 0x18927e0)
        /app/cmd/swagger/commands/generate/shared.go:179 +0x225
github.com/go-swagger/go-swagger/cmd/swagger/commands/generate.(*Model).Execute(0xc00020d7a0, 0xc00008a9b0, 0x0, 0x5, 0xc00020d7a0, 0x1)
        /app/cmd/swagger/commands/generate/model.go:97 +0xa1
github.com/jessevdk/go-flags.(*Parser).ParseArgs(0xc00068d620, 0xc000030250, 0x5, 0x5, 0x10, 0x196df08, 0x2a, 0x17ef660, 0xc00036f0e0)
        /go/pkg/mod/github.com/jessevdk/go-flags@v1.4.0/parser.go:316 +0x8c0
github.com/jessevdk/go-flags.(*Parser).Parse(...)
        /go/pkg/mod/github.com/jessevdk/go-flags@v1.4.0/parser.go:186
main.main()
        /app/cmd/swagger/swagger.go:145 +0xafc

```
> I have set DEBUG=1 here
2. `swagger generate model --with-flatten=expand -f swagger/business.yaml`
```shell
2020/07/09 18:02:22 preprocessing spec with option:  expand
2020/07/09 18:02:22 building a plan for generation
2020/07/09 18:02:22 generation target ./
2020/07/09 18:02:22 planning definitions
2020/07/09 18:02:22 planning operations
2020/07/09 18:02:22 grouping operations into packages
2020/07/09 18:02:22 planning meta data and facades
2020/07/09 18:02:22 rendering 1 models
2020/07/09 18:02:22 rendering 1 templates for model Business
2020/07/09 18:02:22 name field Business
2020/07/09 18:02:22 package field models
2020/07/09 18:02:22 creating generated file "business.go" in "models" as definition
2020/07/09 18:02:22 executed template asset:model
2020/07/09 18:02:22 Generation completed!

For this generation to compile you need to have some packages in your GOPATH:

        * github.com/go-openapi/validate
        * github.com/go-openapi/strfmt

You can get these now with: go get -u -f ./...

```
3. comment the last four lines in swagger/business.yaml
```yaml
#...
definitions:
  Business:
    type: object
    properties:
      children:
        type: array
        x-go-custom-tag: bson:"-"
        items:
          $ref: '#/definitions/Business'
      users:
        type: array
        x-go-custom-tag: bson:"users"
        items:
          type: object
#          properties:
#            role:
#              type: string
#              x-go-custom-tag: bson:"role"
```
execute `swagger generate model --with-flatten=expand -f swagger.yaml`
```shell
2020/07/09 18:07:10 preprocessing spec with option:  expand
2020/07/09 18:07:10 building a plan for generation
2020/07/09 18:07:10 generation target ./
2020/07/09 18:07:10 planning definitions
2020/07/09 18:07:10 planning operations
2020/07/09 18:07:10 grouping operations into packages
2020/07/09 18:07:10 planning meta data and facades
2020/07/09 18:07:10 rendering 1 models
2020/07/09 18:07:10 rendering 1 templates for model business
2020/07/09 18:07:10 name field business
2020/07/09 18:07:10 package field models
2020/07/09 18:07:10 creating generated file "business.go" in "models" as definition
2020/07/09 18:07:10 executed template asset:model
2020/07/09 18:07:10 Generation completed!

For this generation to compile you need to have some packages in your GOPATH:

        * github.com/go-openapi/validate
        * github.com/go-openapi/strfmt

You can get these now with: go get -u -f ./...

```
## Environment
swagger version: v0.24.0
go version: go1.14.2 darwin/amd64
OS:  macOS Catalina 10.15.3


Pull request description:
fix(flatten): fixed code generation with circular $ref AND expand option
Whenever generating code (server, client) from a spec with the
--with-flatten=expand option,
the spec document is unusable to resolve a circular $ref.

Although the root cause is most likely a bug in
go-openapi/spec/expander.go, an easier resolution path may be adopted
by cloning the loads.Document using a patched version of Pristine().

This PR requires https://github.com/go-openapi/loads/pull/51, as we
want to use Pristine() on a modified version of the spec inside the
loads.Document.

* fixes #2346

Signed-off-by: Frederic BIDON <fredbi@yahoo.com>

Patch:
diff --git a/fixtures/bugs/2346/business.yaml b/fixtures/bugs/2346/business.yaml
new file mode 100644
index 00000000..b7aaa6b6
--- /dev/null
+++ b/fixtures/bugs/2346/business.yaml
@@ -0,0 +1,53 @@
+swagger: "2.0"
+info:
+  description: "Business Sub API"
+  version: "1.0.0"
+  title: "Business Sub-API"
+
+host: "127.0.0.1:8080"
+basePath: "/rest/ms"
+
+tags:
+  - name: "business"
+    description: "business info"
+    externalDocs:
+      description: "Find out more"
+      url: "http://swagger.io"
+
+paths:
+  /business:
+    post:
+      summary: Create a business
+      operationId: createBusiness
+      tags:
+        - "business"
+      parameters:
+        - name: body
+          in: body
+          required: true
+          schema:
+            $ref: '#/definitions/Business'
+      responses:
+        200:
+          description: OK
+          schema:
+            type: object
+definitions:
+  Business:
+    type: object
+    properties:
+      children:
+        type: array
+        x-go-custom-tag: bson:"-"
+        items:
+          $ref: '#/definitions/Business'
+      users:
+        type: array
+        x-go-custom-tag: bson:"users"
+        items:
+          type: object
+          properties:
+            role:
+              type: string
+              x-go-custom-tag: bson:"role"
+
diff --git a/fixtures/bugs/2346/swagger.yaml b/fixtures/bugs/2346/swagger.yaml
new file mode 100644
index 00000000..28dab211
--- /dev/null
+++ b/fixtures/bugs/2346/swagger.yaml
@@ -0,0 +1,24 @@
+swagger: "2.0"
+info:
+  description: "ms api"
+  version: "1.0.0"
+  title: "ms api"
+
+host: "127.0.0.1:8613"
+basePath: "/rest/ms"
+
+tags:
+  - name: "business"
+    description: "business info"
+    externalDocs:
+      description: "Find out more"
+      url: "http://swagger.io"
+schemes:
+  - "http"
+
+security:
+  - api_key: []
+
+paths:
+  /business:
+    $ref: "business.yaml#/paths/~1business"
diff --git a/generator/spec.go b/generator/spec.go
index badae6ee..df3528a6 100644
--- a/generator/spec.go
+++ b/generator/spec.go
@@ -87,6 +87,16 @@ func (g *GenOpts) validateAndFlattenSpec() (*loads.Document, error) {
 		return nil, err
 	}
 
+	if g.FlattenOpts.Expand {
+		// for a similar reason as the one mentioned above for validate,
+		// schema expansion alters the internal doc cache in the spec.
+		// This nasty bug (in spec expander) affects circular references.
+		// So we need to reload the spec from a clone.
+		// Notice that since the spec inside the document has been modified, we should
+		// ensure that Pristine refreshes its row root document.
+		specDoc = specDoc.Pristine()
+	}
+
 	// yields the preprocessed spec document
 	return specDoc, nil
 }
diff --git a/go.mod b/go.mod
index 9dddf523..00d20618 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
 	github.com/go-openapi/analysis v0.22.0
 	github.com/go-openapi/errors v0.21.0
 	github.com/go-openapi/inflect v0.19.0
-	github.com/go-openapi/loads v0.21.2
+	github.com/go-openapi/loads v0.21.5
 	github.com/go-openapi/runtime v0.26.0
 	github.com/go-openapi/spec v0.20.13
 	github.com/go-openapi/strfmt v0.21.10
diff --git a/go.sum b/go.sum
index 175a9a48..0b642344 100644
--- a/go.sum
+++ b/go.sum
@@ -87,12 +87,10 @@ github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY=
-github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo=
 github.com/go-openapi/analysis v0.22.0 h1:wQ/d07nf78HNj4u+KiSY0sT234IAyePPbMgpUjUJQR0=
 github.com/go-openapi/analysis v0.22.0/go.mod h1:acDnkkCI2QxIo8sSIPgmp1wUlRohV7vfGtAIVae73b0=
 github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
 github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
-github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
 github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY=
 github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho=
 github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
@@ -102,21 +100,18 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34
 github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
 github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
 github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
-github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
 github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
 github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
 github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g=
-github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro=
-github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw=
+github.com/go-openapi/loads v0.21.5 h1:jDzF4dSoHw6ZFADCGltDb2lE4F6De7aWSpe+IcsRzT0=
+github.com/go-openapi/loads v0.21.5/go.mod h1:PxTsnFBoBe+z89riT+wYt3prmSBP6GDAQh2l9H1Flz8=
 github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc=
 github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ=
 github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
-github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
 github.com/go-openapi/spec v0.20.13 h1:XJDIN+dLH6vqXgafnl5SUIMnzaChQ6QTo0/UPMbkIaE=
 github.com/go-openapi/spec v0.20.13/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
 github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg=
 github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
-github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
 github.com/go-openapi/strfmt v0.21.10 h1:JIsly3KXZB/Qf4UzvzJpg4OELH/0ASDQsyk//TTBDDk=
 github.com/go-openapi/strfmt v0.21.10/go.mod h1:vNDMwbilnl7xKiO/Ve/8H8Bb2JIInBnH+lqiw6QWgis=
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
@@ -344,10 +339,8 @@ github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9r
 github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
 github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
-github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
 github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
 github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
-github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
 github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -357,7 +350,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
 go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
-go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
 go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk=
 go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -481,7 +473,6 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=


Test patch:
diff --git a/generator/server_test.go b/generator/server_test.go
index 944b3188..07dd0a78 100644
--- a/generator/server_test.go
+++ b/generator/server_test.go
@@ -441,3 +441,40 @@ func TestServer_Issue1816(t *testing.T) {
 	assertInCode(t, `"api_key": []`, res)
 	assertNotInCode(t, `"api_key": null`, res)
 }
+
+func TestServer_Issue2346(t *testing.T) {
+	defer discardOutput()()
+
+	targetdir, err := os.MkdirTemp(".", "swagger_server")
+	require.NoErrorf(t, err, "failed to create a test target directory: %v", err)
+	t.Cleanup(func() {
+		_ = os.RemoveAll(targetdir)
+	})
+
+	cwd := testCwd(t)
+	require.NoErrorf(t, os.Chdir(targetdir), "failed to chdir to test target directory: %v", err)
+	defer func() {
+		_ = os.Chdir(cwd)
+	}()
+
+	t.Run("should build server with flatten Expand optio", func(t *testing.T) {
+		opts := testGenOpts()
+		opts.Target = "x"
+		opts.FlattenOpts.Expand = true // this issue pops up spcifically when using this option
+		opts.Spec = filepath.Join("..", "..", "fixtures", "bugs", "2346", "swagger.yaml")
+		require.NoError(t, os.Mkdir(opts.Target, 0o755))
+
+		require.NoError(t, GenerateServer("api-2346", nil, nil, opts))
+	})
+
+	t.Run("should build server with flatten Minimal (no expand)", func(t *testing.T) {
+		opts := testGenOpts()
+		opts.Target = "y"
+		opts.FlattenOpts.Minimal = true
+		opts.FlattenOpts.Expand = false
+		opts.Spec = filepath.Join("..", "..", "fixtures", "bugs", "2346", "swagger.yaml")
+		require.NoError(t, os.Mkdir(opts.Target, 0o755))
+
+		require.NoError(t, GenerateServer("api-2346", nil, nil, opts))
+	})
+}