Repository: deepmap/oapi-codegen
Pull request #812 (2022-10-24 02:46:05)

Fixed an issue where null values were incorrectly generated when AnyOf was set
Fix for https://github.com/deepmap/oapi-codegen/issues/811.


Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..61bacce
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,7 @@
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+version: 2
+updates:
+  - package-ecosystem: "gomod"
+    directory: "/"
+    schedule:
+      interval: "weekly"
diff --git a/examples/petstore-expanded/gin/api/petstore-server.gen.go b/examples/petstore-expanded/gin/api/petstore-server.gen.go
index b05b843..8dabdd9 100644
--- a/examples/petstore-expanded/gin/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/gin/api/petstore-server.gen.go
@@ -38,6 +38,7 @@ type ServerInterface interface {
 type ServerInterfaceWrapper struct {
 	Handler            ServerInterface
 	HandlerMiddlewares []MiddlewareFunc
+	ErrorHandler       func(*gin.Context, error, int)
 }
 
 type MiddlewareFunc func(c *gin.Context)
@@ -54,7 +55,7 @@ func (siw *ServerInterfaceWrapper) FindPets(c *gin.Context) {
 
 	err = runtime.BindQueryParameter("form", true, false, "tags", c.Request.URL.Query(), &params.Tags)
 	if err != nil {
-		c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter tags: %s", err)})
+		siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter tags: %s", err), http.StatusBadRequest)
 		return
 	}
 
@@ -62,7 +63,7 @@ func (siw *ServerInterfaceWrapper) FindPets(c *gin.Context) {
 
 	err = runtime.BindQueryParameter("form", true, false, "limit", c.Request.URL.Query(), &params.Limit)
 	if err != nil {
-		c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter limit: %s", err)})
+		siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter limit: %s", err), http.StatusBadRequest)
 		return
 	}
 
@@ -93,7 +94,7 @@ func (siw *ServerInterfaceWrapper) DeletePet(c *gin.Context) {
 
 	err = runtime.BindStyledParameter("simple", false, "id", c.Param("id"), &id)
 	if err != nil {
-		c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter id: %s", err)})
+		siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %s", err), http.StatusBadRequest)
 		return
 	}
 
@@ -114,7 +115,7 @@ func (siw *ServerInterfaceWrapper) FindPetByID(c *gin.Context) {
 
 	err = runtime.BindStyledParameter("simple", false, "id", c.Param("id"), &id)
 	if err != nil {
-		c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter id: %s", err)})
+		siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %s", err), http.StatusBadRequest)
 		return
 	}
 
@@ -127,8 +128,9 @@ func (siw *ServerInterfaceWrapper) FindPetByID(c *gin.Context) {
 
 // GinServerOptions provides options for the Gin server.
 type GinServerOptions struct {
-	BaseURL     string
-	Middlewares []MiddlewareFunc
+	BaseURL      string
+	Middlewares  []MiddlewareFunc
+	ErrorHandler func(*gin.Context, error, int)
 }
 
 // RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
@@ -138,9 +140,19 @@ func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine {
 
 // RegisterHandlersWithOptions creates http.Handler with additional options
 func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine {
+
+	errorHandler := options.ErrorHandler
+
+	if errorHandler == nil {
+		errorHandler = func(c *gin.Context, err error, statusCode int) {
+			c.JSON(statusCode, gin.H{"msg": err.Error()})
+		}
+	}
+
 	wrapper := ServerInterfaceWrapper{
 		Handler:            si,
 		HandlerMiddlewares: options.Middlewares,
+		ErrorHandler:       errorHandler,
 	}
 
 	router.GET(options.BaseURL+"/pets", wrapper.FindPets)
diff --git a/go.mod b/go.mod
index c06974e..9dcd51f 100644
--- a/go.mod
+++ b/go.mod
@@ -2,17 +2,17 @@ module github.com/deepmap/oapi-codegen
 
 require (
 	github.com/apapsch/go-jsonmerge/v2 v2.0.0
-	github.com/getkin/kin-openapi v0.104.0
+	github.com/getkin/kin-openapi v0.107.0
 	github.com/gin-gonic/gin v1.8.1
 	github.com/go-chi/chi/v5 v5.0.7
 	github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219
 	github.com/google/uuid v1.3.0
 	github.com/gorilla/mux v1.8.0
-	github.com/labstack/echo/v4 v4.9.0
+	github.com/labstack/echo/v4 v4.9.1
 	github.com/lestrrat-go/jwx v1.2.25
 	github.com/matryer/moq v0.2.7
-	github.com/stretchr/testify v1.8.0
-	golang.org/x/tools v0.1.12
+	github.com/stretchr/testify v1.8.1
+	golang.org/x/tools v0.2.0
 	gopkg.in/yaml.v2 v2.4.0
 )
 
@@ -24,13 +24,13 @@ require (
 	github.com/go-openapi/swag v0.21.1 // indirect
 	github.com/go-playground/locales v0.14.0 // indirect
 	github.com/go-playground/universal-translator v0.18.0 // indirect
-	github.com/go-playground/validator/v10 v10.11.0 // indirect
-	github.com/goccy/go-json v0.9.7 // indirect
+	github.com/go-playground/validator/v10 v10.11.1 // indirect
+	github.com/goccy/go-json v0.9.11 // indirect
 	github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
 	github.com/invopop/yaml v0.1.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/labstack/gommon v0.3.1 // indirect
+	github.com/labstack/gommon v0.4.0 // indirect
 	github.com/leodido/go-urn v1.2.1 // indirect
 	github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
 	github.com/lestrrat-go/blackmagic v1.0.0 // indirect
@@ -38,26 +38,26 @@ require (
 	github.com/lestrrat-go/iter v1.0.1 // indirect
 	github.com/lestrrat-go/option v1.0.0 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
-	github.com/mattn/go-colorable v0.1.12 // indirect
-	github.com/mattn/go-isatty v0.0.14 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.16 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
-	github.com/pelletier/go-toml/v2 v2.0.1 // indirect
+	github.com/pelletier/go-toml/v2 v2.0.5 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/stretchr/objx v0.4.0 // indirect
+	github.com/stretchr/objx v0.5.0 // indirect
 	github.com/ugorji/go/codec v1.2.7 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
-	github.com/valyala/fasttemplate v1.2.1 // indirect
-	golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 // indirect
-	golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
-	golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
-	golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
-	golang.org/x/text v0.3.7 // indirect
+	github.com/valyala/fasttemplate v1.2.2 // indirect
+	golang.org/x/crypto v0.1.0 // indirect
+	golang.org/x/mod v0.6.0 // indirect
+	golang.org/x/net v0.1.0 // indirect
+	golang.org/x/sys v0.1.0 // indirect
+	golang.org/x/text v0.4.0 // indirect
 	golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
 	golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
-	google.golang.org/protobuf v1.28.0 // indirect
+	google.golang.org/protobuf v1.28.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
 
diff --git a/go.sum b/go.sum
index ad12a43..c8c1e6b 100644
--- a/go.sum
+++ b/go.sum
@@ -10,8 +10,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
-github.com/getkin/kin-openapi v0.104.0 h1:DZ2F89M/nnjgmIq08Fr/rxmtHmC9A0RVqFWr/ZPdYf4=
-github.com/getkin/kin-openapi v0.104.0/go.mod h1:9Dhr+FasATJZjS4iOLvB0hkaxgYdulrNYm2e9epLWOo=
+github.com/getkin/kin-openapi v0.107.0 h1:bxhL6QArW7BXQj8NjXfIJQy680NsMKd25nwhvpCXchg=
+github.com/getkin/kin-openapi v0.107.0/go.mod h1:9Dhr+FasATJZjS4iOLvB0hkaxgYdulrNYm2e9epLWOo=
 github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
@@ -29,10 +29,11 @@ github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb
 github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
 github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
 github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
-github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw=
-github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
-github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
+github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
+github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
 github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
+github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
 github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
@@ -60,10 +61,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY=
-github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
-github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
-github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
+github.com/labstack/echo/v4 v4.9.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+Y=
+github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo=
+github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
+github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
 github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
 github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
 github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
@@ -86,10 +87,11 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
 github.com/matryer/moq v0.2.7 h1:RtpiPUM8L7ZSCbSwK+QcZH/E9tgqAkFjKQxsRs25b4w=
 github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk=
 github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
-github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
-github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
-github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -98,8 +100,8 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
-github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
+github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
+github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -110,38 +112,41 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA
 github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
 github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
 github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
 github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
 github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
+github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
 github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 h1:NUzdAbFtCJSXU20AOXgeqaUwg8Ypg4MPYmL+d+rsB5c=
-golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
 golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -153,21 +158,23 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
 golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
-golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
+golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -175,8 +182,8 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
 golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
-google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/pkg/codegen/inline.go b/pkg/codegen/inline.go
index eedafa7..e722337 100644
--- a/pkg/codegen/inline.go
+++ b/pkg/codegen/inline.go
@@ -16,6 +16,7 @@ package codegen
 import (
 	"bytes"
 	"compress/gzip"
+	"context"
 	"encoding/base64"
 	"fmt"
 	"text/template"
@@ -26,6 +27,8 @@ import (
 // GenerateInlinedSpec generates a gzipped, base64 encoded JSON representation of the
 // swagger definition, which we embed inside the generated code.
 func GenerateInlinedSpec(t *template.Template, importMapping importMap, swagger *openapi3.T) (string, error) {
+	// ensure that any external file references are embedded into the embedded spec
+	swagger.InternalizeRefs(context.Background(), nil)
 	// Marshal to json
 	encoded, err := swagger.MarshalJSON()
 	if err != nil {
diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go
index ff1ea9c..43d59e0 100644
--- a/pkg/codegen/operations.go
+++ b/pkg/codegen/operations.go
@@ -510,10 +510,10 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) {
 					return nil, fmt.Errorf("error generating default OperationID for %s/%s: %s",
 						opName, requestPath, err)
 				}
-				op.OperationID = op.OperationID
 			} else {
 				op.OperationID = ToCamelCase(op.OperationID)
 			}
+			op.OperationID = typeNamePrefix(op.OperationID) + op.OperationID
 
 			// These are parameters defined for the specific path method that
 			// we're iterating over.
diff --git a/pkg/codegen/templates/gin/gin-register.tmpl b/pkg/codegen/templates/gin/gin-register.tmpl
index 5362dd7..188cbb8 100644
--- a/pkg/codegen/templates/gin/gin-register.tmpl
+++ b/pkg/codegen/templates/gin/gin-register.tmpl
@@ -2,6 +2,7 @@
 type GinServerOptions struct {
     BaseURL string
     Middlewares []MiddlewareFunc
+    ErrorHandler func(*gin.Context, error, int)
 }
 
 // RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
@@ -11,13 +12,23 @@ func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine {
 
 // RegisterHandlersWithOptions creates http.Handler with additional options
 func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine {
-{{if .}}wrapper := ServerInterfaceWrapper{
-Handler: si,
-HandlerMiddlewares: options.Middlewares,
-}
-{{end}}
-{{range .}}
-router.{{.Method }}(options.BaseURL+"{{.Path | swaggerUriToGinUri }}", wrapper.{{.OperationId}})
-{{end}}
-return router
+    {{if .}}
+    errorHandler := options.ErrorHandler
+
+    if errorHandler == nil {
+        errorHandler = func(c *gin.Context, err error, statusCode int) {
+            c.JSON(statusCode, gin.H{"msg": err.Error()})
+        }
+    }
+
+    wrapper := ServerInterfaceWrapper{
+        Handler: si,
+        HandlerMiddlewares: options.Middlewares,
+        ErrorHandler: errorHandler,
+    }
+    {{end}}
+    {{range .}}
+    router.{{.Method }}(options.BaseURL+"{{.Path | swaggerUriToGinUri }}", wrapper.{{.OperationId}})
+    {{end}}
+    return router
 }
diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl
index 59d03f5..fae5c04 100644
--- a/pkg/codegen/templates/gin/gin-wrappers.tmpl
+++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl
@@ -2,6 +2,7 @@
 type ServerInterfaceWrapper struct {
     Handler ServerInterface
     HandlerMiddlewares []MiddlewareFunc
+    ErrorHandler func(*gin.Context, error, int)
 }
 
 type MiddlewareFunc func(c *gin.Context)
@@ -24,14 +25,14 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
   {{if .IsJson}}
   err = json.Unmarshal([]byte(c.Query("{{.ParamName}}")), &{{$varName}})
   if err != nil {
-    c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unmarshaling parameter '{{.ParamName}}' as JSON"})
+    siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON"), http.StatusBadRequest)
     return
   }
   {{end}}
   {{if .IsStyled}}
   err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", c.Param("{{.ParamName}}"), &{{$varName}})
   if err != nil {
-    c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)})
+    siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %s", err), http.StatusBadRequest)
     return
   }
   {{end}}
@@ -61,21 +62,22 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
           var value {{.TypeDef}}
           err = json.Unmarshal([]byte(paramValue), &value)
           if err != nil {
-            c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unmarshaling parameter '{{.ParamName}}' as JSON"})
-            return
+            siw.ErrorHandler(c, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %s", err), http.StatusBadRequest) {
           }
 
           params.{{.GoName}} = {{if not .Required}}&{{end}}value
         {{end}}
         }{{if .Required}} else {
-            c.JSON(http.StatusBadRequest, gin.H{"msg": "Query argument {{.ParamName}} is required, but not found"})
-            return
+           if !siw.ErrorHandler(c, fmt.Errorf("Query argument {{.ParamName}} is required, but not found: %s", err), http.StatusBadRequest) {
+             return
+           }
         }{{end}}
       {{end}}
+
       {{if .IsStyled}}
       err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", c.Request.URL.Query(), &params.{{.GoName}})
       if err != nil {
-        c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)})
+        siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %s", err), http.StatusBadRequest)
         return
       }
       {{end}}
@@ -89,7 +91,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
           var {{.GoName}} {{.TypeDef}}
           n := len(valueList)
           if n != 1 {
-            c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Expected one value for {{.ParamName}}, got %d", n)})
+            siw.ErrorHandler(c, fmt.Errorf("Expected one value for {{.ParamName}}, got %d", n), http.StatusBadRequest)
             return
           }
 
@@ -100,7 +102,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
         {{if .IsJson}}
           err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}})
           if err != nil {
-            c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unmarshaling parameter '{{.ParamName}}' as JSON"})
+            siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON"), http.StatusBadRequest)
             return
           }
         {{end}}
@@ -108,7 +110,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
         {{if .IsStyled}}
           err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}})
           if err != nil {
-            c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)})
+            siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %s", err), http.StatusBadRequest)
             return
           }
         {{end}}
@@ -116,7 +118,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
           params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
 
         } {{if .Required}}else {
-            c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Header parameter {{.ParamName}} is required, but not found: %s", err)})
+            siw.ErrorHandler(c, fmt.Errorf("Header parameter {{.ParamName}} is required, but not found: %s", err), http.StatusBadRequest)
             return
         }{{end}}
 
@@ -137,14 +139,14 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
         var decoded string
         decoded, err := url.QueryUnescape(cookie.Value)
         if err != nil {
-          c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unescaping cookie parameter '{{.ParamName}}'"})
-          return
+            siw.ErrorHandler(c, fmt.Errorf("Error unescaping cookie parameter '{{.ParamName}}'"), http.StatusBadRequest)
+            return
         }
 
         err = json.Unmarshal([]byte(decoded), &value)
         if err != nil {
-          c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unmarshaling parameter '{{.ParamName}}' as JSON"})
-          return
+            siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON"), http.StatusBadRequest)
+            return
         }
 
         params.{{.GoName}} = {{if not .Required}}&{{end}}value
@@ -154,8 +156,8 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
         var value {{.TypeDef}}
         err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value)
         if err != nil {
-          c.JSON(http.StatusBadRequest, gin.H{"msg": "Invalid format for parameter {{.ParamName}}: %s"})
-          return
+            siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %s", err), http.StatusBadRequest)
+            return
         }
         params.{{.GoName}} = {{if not .Required}}&{{end}}value
       {{end}}
@@ -163,7 +165,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
       }
 
       {{- if .Required}} else {
-        c.JSON(http.StatusBadRequest, gin.H{"msg": "Query argument {{.ParamName}} is required, but not found"})
+        siw.ErrorHandler(c, fmt.Errorf("Query argument {{.ParamName}} is required, but not found"), http.StatusBadRequest)
         return
       }
       {{- end}}
diff --git a/pkg/codegen/templates/union.tmpl b/pkg/codegen/templates/union.tmpl
index eb015be..b758a82 100644
--- a/pkg/codegen/templates/union.tmpl
+++ b/pkg/codegen/templates/union.tmpl
@@ -100,10 +100,12 @@
               }
             }
             {{range .Schema.Properties}}
+            {{if not .Required}}if t.{{.GoFieldName}} != nil { {{end}}
                 object["{{.JsonFieldName}}"], err = json.Marshal(t.{{.GoFieldName}})
                 if err != nil {
                     return nil, fmt.Errorf("error marshaling '{{.JsonFieldName}}': %w", err)
                 }
+            {{if not .Required}} }{{end}}
             {{end -}}
             b, err = json.Marshal(object)
         {{end -}}


Test patch:
diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go
index 2553471..ce8c6d9 100644
--- a/internal/test/components/components.gen.go
+++ b/internal/test/components/components.gen.go
@@ -987,19 +987,25 @@ func (t OneOfObject10) MarshalJSON() ([]byte, error) {
 		}
 	}
 
-	object["one"], err = json.Marshal(t.One)
-	if err != nil {
-		return nil, fmt.Errorf("error marshaling 'one': %w", err)
+	if t.One != nil {
+		object["one"], err = json.Marshal(t.One)
+		if err != nil {
+			return nil, fmt.Errorf("error marshaling 'one': %w", err)
+		}
 	}
 
-	object["three"], err = json.Marshal(t.Three)
-	if err != nil {
-		return nil, fmt.Errorf("error marshaling 'three': %w", err)
+	if t.Three != nil {
+		object["three"], err = json.Marshal(t.Three)
+		if err != nil {
+			return nil, fmt.Errorf("error marshaling 'three': %w", err)
+		}
 	}
 
-	object["two"], err = json.Marshal(t.Two)
-	if err != nil {
-		return nil, fmt.Errorf("error marshaling 'two': %w", err)
+	if t.Two != nil {
+		object["two"], err = json.Marshal(t.Two)
+		if err != nil {
+			return nil, fmt.Errorf("error marshaling 'two': %w", err)
+		}
 	}
 	b, err = json.Marshal(object)
 	return b, err
@@ -1509,9 +1515,11 @@ func (t OneOfObject4) MarshalJSON() ([]byte, error) {
 		}
 	}
 
-	object["fixedProperty"], err = json.Marshal(t.FixedProperty)
-	if err != nil {
-		return nil, fmt.Errorf("error marshaling 'fixedProperty': %w", err)
+	if t.FixedProperty != nil {
+		object["fixedProperty"], err = json.Marshal(t.FixedProperty)
+		if err != nil {
+			return nil, fmt.Errorf("error marshaling 'fixedProperty': %w", err)
+		}
 	}
 	b, err = json.Marshal(object)
 	return b, err
@@ -1824,9 +1832,11 @@ func (t OneOfObject8) MarshalJSON() ([]byte, error) {
 		}
 	}
 
-	object["fixed"], err = json.Marshal(t.Fixed)
-	if err != nil {
-		return nil, fmt.Errorf("error marshaling 'fixed': %w", err)
+	if t.Fixed != nil {
+		object["fixed"], err = json.Marshal(t.Fixed)
+		if err != nil {
+			return nil, fmt.Errorf("error marshaling 'fixed': %w", err)
+		}
 	}
 	b, err = json.Marshal(object)
 	return b, err
@@ -1953,6 +1963,7 @@ func (t OneOfObject9) MarshalJSON() ([]byte, error) {
 	if err != nil {
 		return nil, fmt.Errorf("error marshaling 'type': %w", err)
 	}
+
 	b, err = json.Marshal(object)
 	return b, err
 }
diff --git a/internal/test/components/components_test.go b/internal/test/components/components_test.go
index bcb34d7..2034c96 100644
--- a/internal/test/components/components_test.go
+++ b/internal/test/components/components_test.go
@@ -204,7 +204,7 @@ func TestAnyOf(t *testing.T) {
 }
 
 func TestMarshalWhenNoUnionValueSet(t *testing.T) {
-	const expected = `{"one":null,"three":null,"two":null}`
+	const expected = `{}`
 
 	var dst OneOfObject10
 
diff --git a/internal/test/externalref/externalref.gen.go b/internal/test/externalref/externalref.gen.go
index 698bc3f..b9b62d1 100644
--- a/internal/test/externalref/externalref.gen.go
+++ b/internal/test/externalref/externalref.gen.go
@@ -19,16 +19,18 @@ import (
 
 // Container defines model for Container.
 type Container struct {
-	ObjectA *externalRef0.ObjectA `json:"object_a,omitempty"`
-	ObjectB *externalRef1.ObjectB `json:"object_b,omitempty"`
+	ObjectA *externalRef0.ObjectA   `json:"object_a,omitempty"`
+	ObjectB *externalRef1.ObjectB   `json:"object_b,omitempty"`
+	ObjectC *map[string]interface{} `json:"object_c,omitempty"`
 }
 
 // Base64 encoded, gzipped, json marshaled Swagger object
 var swaggerSpec = []string{
 
-	"H4sIAAAAAAAC/4zPQcrCMBAF4Lu8/1+GpOAuu9YDeASZhqmNtsmQBEFK7i4pihsXZvUeYb5hNri4Sgwc",
-	"SobdkN3MK+3xGEMhHzi1IikKp+J5/4rjlV05U8v/iSdYaCPkbnTh3mRhpx+0Ln/mg5uXbE77bI+q3sz4",
-	"jRl+YgbU9hR8mGJjii8LwwIKd07Zx9BK2yUcSDwsDrrTHRSEytyuqfUZAAD//0P8tE0FAQAA",
+	"H4sIAAAAAAAC/5yPQU7EMAxF72JYRtOR2GXHcAC4AfJkPNSotaPEIKEqd0dJKa1gQcUqtvzf/z8TBB2j",
+	"Coll8BPk0NOIbXxQMWShVJeYNFIypnbS8ysFe8Y63ya6goebbjXqvly6x6a7h+IW5LwPOW2Q8BfyrSul",
+	"OFgyf5UWHKm+9hEJPGRLLC//qrbGnHbHlB8fwsuFjVVweNrglt7ILegsn1GWqzZXtqHewME7pcwqdane",
+	"kQQjg4e7w/FwBAcRra+NSvkMAAD//3vXjDblAQAA",
 }
 
 // GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/externalref/object_c.json b/internal/test/externalref/object_c.json
new file mode 100644
index 0000000..b85043d
--- /dev/null
+++ b/internal/test/externalref/object_c.json
@@ -0,0 +1,5 @@
+{
+  "type": "object",
+  "properties": {},
+  "additionalProperties": true
+}
diff --git a/internal/test/externalref/packageA/externalref.gen.go b/internal/test/externalref/packageA/externalref.gen.go
index 3b58e3c..01505b1 100644
--- a/internal/test/externalref/packageA/externalref.gen.go
+++ b/internal/test/externalref/packageA/externalref.gen.go
@@ -25,9 +25,9 @@ type ObjectA struct {
 // Base64 encoded, gzipped, json marshaled Swagger object
 var swaggerSpec = []string{
 
-	"H4sIAAAAAAAC/0SNQarDMAwF7/L+X5p4711zgR6hKEZJ3MaysN1FCLl7sVOoNhoYHnPAp6hJWGqBO1D8",
-	"ypE63qcn+3prqDkp5xq4C6HI7dddGQ6l5iALToPUF4+pyf/MMxyGwSr5Fy082qLsh53i9md/Ufst2is3",
-	"4mxnEGROcPLeNoOkLKQBDjBQqmu5zPkJAAD//0utOZO+AAAA",
+	"H4sIAAAAAAAC/4yNQa7CMAxE7zL/LyN1nx1cgCOgtHJpUGtbiVmgyndHSUFsWXmsp3mzY5JNhYmtIu6o",
+	"00Jb6vEy3mmyU4taRKlYpg44bdSuPZUQUa1kvsEDpDeuY4P/hWZE/A1f//CWD4f5DHcP+Dy/znhvZZ4F",
+	"kR/rGiBKnDQjAgGabKkH8VcAAAD//0SMp77dAAAA",
 }
 
 // GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/externalref/spec.yaml b/internal/test/externalref/spec.yaml
index 3f42c7d..ba0ae65 100644
--- a/internal/test/externalref/spec.yaml
+++ b/internal/test/externalref/spec.yaml
@@ -9,3 +9,5 @@ components:
           $ref: ./packageA/spec.yaml#/components/schemas/ObjectA
         object_b:
           $ref: ./packageB/spec.yaml#/components/schemas/ObjectB
+        object_c:
+          $ref: ./object_c.json
diff --git a/internal/test/issues/issue-head-digit-of-operation-id/config.yaml b/internal/test/issues/issue-head-digit-of-operation-id/config.yaml
new file mode 100644
index 0000000..5823c79
--- /dev/null
+++ b/internal/test/issues/issue-head-digit-of-operation-id/config.yaml
@@ -0,0 +1,7 @@
+---
+package: head_digit_of_operation_id
+generate:
+  strict-server: true
+output: issue.gen.go
+output-options:
+  skip-prune: true
diff --git a/internal/test/issues/issue-head-digit-of-operation-id/doc.go b/internal/test/issues/issue-head-digit-of-operation-id/doc.go
new file mode 100644
index 0000000..6faae82
--- /dev/null
+++ b/internal/test/issues/issue-head-digit-of-operation-id/doc.go
@@ -0,0 +1,3 @@
+package head_digit_of_operation_id
+
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go b/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go
new file mode 100644
index 0000000..1760746
--- /dev/null
+++ b/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go
@@ -0,0 +1,23 @@
+// Package head_digit_of_operation_id provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
+package head_digit_of_operation_id
+
+import (
+	"context"
+	"net/http"
+)
+
+type N3GPPFooRequestObject struct {
+}
+
+type N3GPPFooResponseObject interface {
+	VisitN3GPPFooResponse(w http.ResponseWriter) error
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+	// (GET /3gpp/foo)
+	N3GPPFoo(ctx context.Context, request N3GPPFooRequestObject) (N3GPPFooResponseObject, error)
+}
diff --git a/internal/test/issues/issue-head-digit-of-operation-id/spec.yaml b/internal/test/issues/issue-head-digit-of-operation-id/spec.yaml
new file mode 100644
index 0000000..59efb77
--- /dev/null
+++ b/internal/test/issues/issue-head-digit-of-operation-id/spec.yaml
@@ -0,0 +1,7 @@
+openapi: 3.0.2
+info:
+  version: "0.0.1"
+paths:
+  /3gpp/foo:
+    get:
+      operationId: 3GPPFoo
diff --git a/internal/test/server/doc.go b/internal/test/server/doc.go
index 91e93b5..1f7a617 100644
--- a/internal/test/server/doc.go
+++ b/internal/test/server/doc.go
@@ -1,4 +1,8 @@
 package server
 
 //go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml ../test-schema.yaml
-//go:generate go run github.com/matryer/moq -out server_moq.gen.go . ServerInterface
+
+// This is commented out because the server_mog.gen.go keeps changing for no good reason, and
+// so, precommit checks fail. We need to regenerate this file occasionally manually.
+// TODO(mromaszewicz) - figure out why this file drifts and fix it.
+// go:generate go run github.com/matryer/moq -out server_moq.gen.go . ServerInterface
diff --git a/internal/test/server/server_moq.gen.go b/internal/test/server/server_moq.gen.go
index aa22e65..80bc73a 100644
--- a/internal/test/server/server_moq.gen.go
+++ b/internal/test/server/server_moq.gen.go
@@ -14,46 +14,46 @@ var _ ServerInterface = &ServerInterfaceMock{}
 
 // ServerInterfaceMock is a mock implementation of ServerInterface.
 //
-// 	func TestSomethingThatUsesServerInterface(t *testing.T) {
+//	func TestSomethingThatUsesServerInterface(t *testing.T) {
 //
-// 		// make and configure a mocked ServerInterface
-// 		mockedServerInterface := &ServerInterfaceMock{
-// 			CreateResourceFunc: func(w http.ResponseWriter, r *http.Request, argument string)  {
-// 				panic("mock out the CreateResource method")
-// 			},
-// 			CreateResource2Func: func(w http.ResponseWriter, r *http.Request, inlineArgument int, params CreateResource2Params)  {
-// 				panic("mock out the CreateResource2 method")
-// 			},
-// 			GetEveryTypeOptionalFunc: func(w http.ResponseWriter, r *http.Request)  {
-// 				panic("mock out the GetEveryTypeOptional method")
-// 			},
-// 			GetReservedKeywordFunc: func(w http.ResponseWriter, r *http.Request)  {
-// 				panic("mock out the GetReservedKeyword method")
-// 			},
-// 			GetResponseWithReferenceFunc: func(w http.ResponseWriter, r *http.Request)  {
-// 				panic("mock out the GetResponseWithReference method")
-// 			},
-// 			GetSimpleFunc: func(w http.ResponseWriter, r *http.Request)  {
-// 				panic("mock out the GetSimple method")
-// 			},
-// 			GetWithArgsFunc: func(w http.ResponseWriter, r *http.Request, params GetWithArgsParams)  {
-// 				panic("mock out the GetWithArgs method")
-// 			},
-// 			GetWithContentTypeFunc: func(w http.ResponseWriter, r *http.Request, contentType GetWithContentTypeParamsContentType)  {
-// 				panic("mock out the GetWithContentType method")
-// 			},
-// 			GetWithReferencesFunc: func(w http.ResponseWriter, r *http.Request, globalArgument int64, argument string)  {
-// 				panic("mock out the GetWithReferences method")
-// 			},
-// 			UpdateResource3Func: func(w http.ResponseWriter, r *http.Request, pFallthrough int)  {
-// 				panic("mock out the UpdateResource3 method")
-// 			},
-// 		}
+//		// make and configure a mocked ServerInterface
+//		mockedServerInterface := &ServerInterfaceMock{
+//			CreateResourceFunc: func(w http.ResponseWriter, r *http.Request, argument string)  {
+//				panic("mock out the CreateResource method")
+//			},
+//			CreateResource2Func: func(w http.ResponseWriter, r *http.Request, inlineArgument int, params CreateResource2Params)  {
+//				panic("mock out the CreateResource2 method")
+//			},
+//			GetEveryTypeOptionalFunc: func(w http.ResponseWriter, r *http.Request)  {
+//				panic("mock out the GetEveryTypeOptional method")
+//			},
+//			GetReservedKeywordFunc: func(w http.ResponseWriter, r *http.Request)  {
+//				panic("mock out the GetReservedKeyword method")
+//			},
+//			GetResponseWithReferenceFunc: func(w http.ResponseWriter, r *http.Request)  {
+//				panic("mock out the GetResponseWithReference method")
+//			},
+//			GetSimpleFunc: func(w http.ResponseWriter, r *http.Request)  {
+//				panic("mock out the GetSimple method")
+//			},
+//			GetWithArgsFunc: func(w http.ResponseWriter, r *http.Request, params GetWithArgsParams)  {
+//				panic("mock out the GetWithArgs method")
+//			},
+//			GetWithContentTypeFunc: func(w http.ResponseWriter, r *http.Request, contentType GetWithContentTypeParamsContentType)  {
+//				panic("mock out the GetWithContentType method")
+//			},
+//			GetWithReferencesFunc: func(w http.ResponseWriter, r *http.Request, globalArgument int64, argument string)  {
+//				panic("mock out the GetWithReferences method")
+//			},
+//			UpdateResource3Func: func(w http.ResponseWriter, r *http.Request, pFallthrough int)  {
+//				panic("mock out the UpdateResource3 method")
+//			},
+//		}
 //
-// 		// use mockedServerInterface in code that requires ServerInterface
-// 		// and then make assertions.
+//		// use mockedServerInterface in code that requires ServerInterface
+//		// and then make assertions.
 //
-// 	}
+//	}
 type ServerInterfaceMock struct {
 	// CreateResourceFunc mocks the CreateResource method.
 	CreateResourceFunc func(w http.ResponseWriter, r *http.Request, argument string)
@@ -208,7 +208,8 @@ func (mock *ServerInterfaceMock) CreateResource(w http.ResponseWriter, r *http.R
 
 // CreateResourceCalls gets all the calls that were made to CreateResource.
 // Check the length with:
-//     len(mockedServerInterface.CreateResourceCalls())
+//
+//	len(mockedServerInterface.CreateResourceCalls())
 func (mock *ServerInterfaceMock) CreateResourceCalls() []struct {
 	W        http.ResponseWriter
 	R        *http.Request
@@ -249,7 +250,8 @@ func (mock *ServerInterfaceMock) CreateResource2(w http.ResponseWriter, r *http.
 
 // CreateResource2Calls gets all the calls that were made to CreateResource2.
 // Check the length with:
-//     len(mockedServerInterface.CreateResource2Calls())
+//
+//	len(mockedServerInterface.CreateResource2Calls())
 func (mock *ServerInterfaceMock) CreateResource2Calls() []struct {
 	W              http.ResponseWriter
 	R              *http.Request
@@ -288,7 +290,8 @@ func (mock *ServerInterfaceMock) GetEveryTypeOptional(w http.ResponseWriter, r *
 
 // GetEveryTypeOptionalCalls gets all the calls that were made to GetEveryTypeOptional.
 // Check the length with:
-//     len(mockedServerInterface.GetEveryTypeOptionalCalls())
+//
+//	len(mockedServerInterface.GetEveryTypeOptionalCalls())
 func (mock *ServerInterfaceMock) GetEveryTypeOptionalCalls() []struct {
 	W http.ResponseWriter
 	R *http.Request
@@ -323,7 +326,8 @@ func (mock *ServerInterfaceMock) GetReservedKeyword(w http.ResponseWriter, r *ht
 
 // GetReservedKeywordCalls gets all the calls that were made to GetReservedKeyword.
 // Check the length with:
-//     len(mockedServerInterface.GetReservedKeywordCalls())
+//
+//	len(mockedServerInterface.GetReservedKeywordCalls())
 func (mock *ServerInterfaceMock) GetReservedKeywordCalls() []struct {
 	W http.ResponseWriter
 	R *http.Request
@@ -358,7 +362,8 @@ func (mock *ServerInterfaceMock) GetResponseWithReference(w http.ResponseWriter,
 
 // GetResponseWithReferenceCalls gets all the calls that were made to GetResponseWithReference.
 // Check the length with:
-//     len(mockedServerInterface.GetResponseWithReferenceCalls())
+//
+//	len(mockedServerInterface.GetResponseWithReferenceCalls())
 func (mock *ServerInterfaceMock) GetResponseWithReferenceCalls() []struct {
 	W http.ResponseWriter
 	R *http.Request
@@ -393,7 +398,8 @@ func (mock *ServerInterfaceMock) GetSimple(w http.ResponseWriter, r *http.Reques
 
 // GetSimpleCalls gets all the calls that were made to GetSimple.
 // Check the length with:
-//     len(mockedServerInterface.GetSimpleCalls())
+//
+//	len(mockedServerInterface.GetSimpleCalls())
 func (mock *ServerInterfaceMock) GetSimpleCalls() []struct {
 	W http.ResponseWriter
 	R *http.Request
@@ -430,7 +436,8 @@ func (mock *ServerInterfaceMock) GetWithArgs(w http.ResponseWriter, r *http.Requ
 
 // GetWithArgsCalls gets all the calls that were made to GetWithArgs.
 // Check the length with:
-//     len(mockedServerInterface.GetWithArgsCalls())
+//
+//	len(mockedServerInterface.GetWithArgsCalls())
 func (mock *ServerInterfaceMock) GetWithArgsCalls() []struct {
 	W      http.ResponseWriter
 	R      *http.Request
@@ -469,7 +476,8 @@ func (mock *ServerInterfaceMock) GetWithContentType(w http.ResponseWriter, r *ht
 
 // GetWithContentTypeCalls gets all the calls that were made to GetWithContentType.
 // Check the length with:
-//     len(mockedServerInterface.GetWithContentTypeCalls())
+//
+//	len(mockedServerInterface.GetWithContentTypeCalls())
 func (mock *ServerInterfaceMock) GetWithContentTypeCalls() []struct {
 	W           http.ResponseWriter
 	R           *http.Request
@@ -510,7 +518,8 @@ func (mock *ServerInterfaceMock) GetWithReferences(w http.ResponseWriter, r *htt
 
 // GetWithReferencesCalls gets all the calls that were made to GetWithReferences.
 // Check the length with:
-//     len(mockedServerInterface.GetWithReferencesCalls())
+//
+//	len(mockedServerInterface.GetWithReferencesCalls())
 func (mock *ServerInterfaceMock) GetWithReferencesCalls() []struct {
 	W              http.ResponseWriter
 	R              *http.Request
@@ -551,7 +560,8 @@ func (mock *ServerInterfaceMock) UpdateResource3(w http.ResponseWriter, r *http.
 
 // UpdateResource3Calls gets all the calls that were made to UpdateResource3.
 // Check the length with:
-//     len(mockedServerInterface.UpdateResource3Calls())
+//
+//	len(mockedServerInterface.UpdateResource3Calls())
 func (mock *ServerInterfaceMock) UpdateResource3Calls() []struct {
 	W            http.ResponseWriter
 	R            *http.Request
diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go
index 5192a0d..837cb70 100644
--- a/internal/test/strict-server/gin/server.gen.go
+++ b/internal/test/strict-server/gin/server.gen.go
@@ -57,6 +57,7 @@ type ServerInterface interface {
 type ServerInterfaceWrapper struct {
 	Handler            ServerInterface
 	HandlerMiddlewares []MiddlewareFunc
+	ErrorHandler       func(*gin.Context, error, int)
 }
 
 type MiddlewareFunc func(c *gin.Context)
@@ -156,20 +157,20 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) {
 		var Header1 string
 		n := len(valueList)
 		if n != 1 {
-			c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Expected one value for header1, got %d", n)})
+			siw.ErrorHandler(c, fmt.Errorf("Expected one value for header1, got %d", n), http.StatusBadRequest)
 			return
 		}
 
 		err = runtime.BindStyledParameterWithLocation("simple", false, "header1", runtime.ParamLocationHeader, valueList[0], &Header1)
 		if err != nil {
-			c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter header1: %s", err)})
+			siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter header1: %s", err), http.StatusBadRequest)
 			return
 		}
 
 		params.Header1 = Header1
 
 	} else {
-		c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Header parameter header1 is required, but not found: %s", err)})
+		siw.ErrorHandler(c, fmt.Errorf("Header parameter header1 is required, but not found: %s", err), http.StatusBadRequest)
 		return
 	}
 
@@ -178,13 +179,13 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) {
 		var Header2 int
 		n := len(valueList)
 		if n != 1 {
-			c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Expected one value for header2, got %d", n)})
+			siw.ErrorHandler(c, fmt.Errorf("Expected one value for header2, got %d", n), http.StatusBadRequest)
 			return
 		}
 
 		err = runtime.BindStyledParameterWithLocation("simple", false, "header2", runtime.ParamLocationHeader, valueList[0], &Header2)
 		if err != nil {
-			c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter header2: %s", err)})
+			siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter header2: %s", err), http.StatusBadRequest)
 			return
 		}
 
@@ -201,8 +202,9 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) {
 
 // GinServerOptions provides options for the Gin server.
 type GinServerOptions struct {
-	BaseURL     string
-	Middlewares []MiddlewareFunc
+	BaseURL      string
+	Middlewares  []MiddlewareFunc
+	ErrorHandler func(*gin.Context, error, int)
 }
 
 // RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
@@ -212,9 +214,19 @@ func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine {
 
 // RegisterHandlersWithOptions creates http.Handler with additional options
 func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine {
+
+	errorHandler := options.ErrorHandler
+
+	if errorHandler == nil {
+		errorHandler = func(c *gin.Context, err error, statusCode int) {
+			c.JSON(statusCode, gin.H{"msg": err.Error()})
+		}
+	}
+
 	wrapper := ServerInterfaceWrapper{
 		Handler:            si,
 		HandlerMiddlewares: options.Middlewares,
+		ErrorHandler:       errorHandler,
 	}
 
 	router.POST(options.BaseURL+"/json", wrapper.JSONExample)
diff --git a/pkg/chi-middleware/oapi_validate_test.go b/pkg/chi-middleware/oapi_validate_test.go
index 8d92ba7..d10df5c 100644
--- a/pkg/chi-middleware/oapi_validate_test.go
+++ b/pkg/chi-middleware/oapi_validate_test.go
@@ -321,7 +321,7 @@ func TestOapiRequestValidatorWithOptions(t *testing.T) {
 	{
 		rec := doGet(t, r, "http://deepmap.ai/protected_resource_401")
 		assert.Equal(t, http.StatusUnauthorized, rec.Code)
-		assert.Equal(t, "test: Security requirements failed\n", rec.Body.String())
+		assert.Equal(t, "test: security requirements failed: unauthorized\n", rec.Body.String())
 		assert.False(t, called, "Handler should not have been called")
 		called = false
 	}
diff --git a/pkg/gin-middleware/oapi_validate_test.go b/pkg/gin-middleware/oapi_validate_test.go
index 3ad2f1c..30ad57f 100644
--- a/pkg/gin-middleware/oapi_validate_test.go
+++ b/pkg/gin-middleware/oapi_validate_test.go
@@ -198,7 +198,7 @@ func TestOapiRequestValidator(t *testing.T) {
 	{
 		rec := doGet(t, g, "http://deepmap.ai/protected_resource_401")
 		assert.Equal(t, http.StatusBadRequest, rec.Code)
-		assert.Equal(t, "test: error in openapi3filter.SecurityRequirementsError: Security requirements failed", rec.Body.String())
+		assert.Equal(t, "test: error in openapi3filter.SecurityRequirementsError: security requirements failed: unauthorized", rec.Body.String())
 		assert.False(t, called, "Handler should not have been called")
 		called = false
 	}