E12023: program creates more than one HTTP instance
What went wrong
The program creates more than one HTTP server instance. Each program should have at most one HTTP server. Multiple HTTP instances would compete for service bindings and create ambiguity about which server handles which routes.
Every HTTP the program creates counts, whatever type the variable holding it is declared as: an HTTP held as the Server trait is still an HTTP.
Worked examples
The [EXAMPLE] section below shows a program that serves HTTP twice, then a single HTTP instance (which serves every registered service), and two programs each with its own application and port (good_split.ek9).
Rationale
A single application has a single service registry with a single set of route bindings. Creating multiple HTTP servers from the same application would duplicate those bindings across servers, wasting resources and creating confusion about which server is authoritative.
If you need multiple HTTP servers (e.g., different ports for admin vs public traffic), use separate programs with separate applications.
How to fix it
Remove the duplicate HTTP instance. Keep a single HTTP server per program.
If you need multiple servers on different ports, split into separate programs with separate applications - a PublicServer with a PublicApp on port 8080, an AdminServer with an AdminApp on 9090 (good_split.ek9 in the [EXAMPLE] section below).
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E12023: program creates more than one HTTP instance
#!ek9 defines module error.e12023.bad defines service HelloService for :/api open health() as GET for :/status <- response as HTTPResponse: () with trait of HTTPResponse override status() as pure <- rtn as Integer: 200 override content() <- rtn as Bytes: Bytes().withUtf8("ok") override contentType() as pure <- rtn as String: "text/plain" default operator ? defines application HelloApp register HelloService() defines program DuplicateHttpDemo() with application of HelloApp props <- NetworkProperties(9090) HTTP(props).serve() HTTP(props).serve()
Fixed: Create one HTTP server - it serves every registered service
#!ek9 defines module error.e12023.good defines service HelloService for :/api open health() as GET for :/status <- response as HTTPResponse: () with trait of HTTPResponse override status() as pure <- rtn as Integer: 200 override content() <- rtn as Bytes: Bytes().withUtf8("ok") override contentType() as pure <- rtn as String: "text/plain" default operator ? defines application HelloApp register HelloService() defines program SingleHttpDemo() with application of HelloApp props <- NetworkProperties(9090) HTTP(props).serve()
Fixed: Servers on different ports: separate programs, each with its own application
#!ek9 defines module error.e12023.good.split defines service PublicService for :/api open health() as GET for :/status <- response as HTTPResponse: () with trait of HTTPResponse override status() as pure <- rtn as Integer: 200 override content() <- rtn as Bytes: Bytes().withUtf8("ok") override contentType() as pure <- rtn as String: "text/plain" default operator ? AdminService for :/admin open health() as GET for :/status <- response as HTTPResponse: () with trait of HTTPResponse override status() as pure <- rtn as Integer: 200 override content() <- rtn as Bytes: Bytes().withUtf8("admin ok") override contentType() as pure <- rtn as String: "text/plain" default operator ? defines application PublicApp register PublicService() AdminApp register AdminService() defines program PublicServer() with application of PublicApp HTTP(NetworkProperties(8080)).serve() AdminServer() with application of AdminApp HTTP(NetworkProperties(9090)).serve()