Super simple Cowboy example throwing :badmap error

Hey all,

Maybe my tired eyes are just tiredly overlooking a tired tiny detail, but for all the staring and experimenting I’ve done I can’t seem to get past this :sweat_smile:

I start iex and start my cowboy module:

$ iex -S mix
Erlang/OTP 26 [erts-14.2.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [dtrace]

Interactive Elixir (1.16.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Cowboy.start
Cowboy server started on port 8080

Then I curl in another terminal:

$ curl http://localhost:8080

And the server throws this:

21:58:22.288 [error] Ranch listener :my_http_listener, connection process #PID<0.247.0>, stream 1 had its request process #PID<0.248.0> exit with reason {:badmap, [{"content-type", "text/html"}]} and stacktrace [{:cowboy_req, :reply, 4, [file: ~c"/cowboy_example/deps/cowboy/src/cowboy_req.erl", line: 837]}, {HelloHandler, :init, 2, [file: ~c"lib/application.ex", line: 19]}, {:cowboy_handler, :execute, 2, [file: ~c"/cowboy_example/deps/cowboy/src/cowboy_handler.erl", line: 37]}, {:cowboy_stream_h, :execute, 3, [file: ~c"/cowboy_example/deps/cowboy/src/cowboy_stream_h.erl", line: 306]}, {:cowboy_stream_h, :request_process, 3, [file: ~c"/cowboy_example/deps/cowboy/src/cowboy_stream_h.erl", line: 295]}, {:proc_lib, :init_p_do_apply, 3, [file: ~c"proc_lib.erl", line: 241]}]

Headers are “:badmap”?

Here’s the sourcecode:

defmodule Cowboy do
  def start() do
    dispatch = :cowboy_router.compile([ {:_, [ {"/", HelloHandler, []} ]} ])

    {:ok, _} = :cowboy.start_clear(
        [{:port, 8080}],
        %{env: %{dispatch: dispatch}}

    IO.puts("Cowboy server started on port 8080")

defmodule HelloHandler do
  def init(req, _opts) do
    {:ok, resp} = :cowboy_req.reply( 200, [{"content-type", "text/html"}], "<h1>Hello World!</h1>", req )
    {:ok, resp, :nostate}

I must be doing something wrong but I’m pretty new to navigating Erlang docs and translating it into Elixir… can you spot it, or help me spot it?

(And mix.exs is configured with {:cowboy, "~> 2.11"} in deps, and extra_applications: [:logger, :cowboy] in application FWIW)

If I look here, it seems the second argument to cowboy_req.reply should be a map (not a tuple) Nine Nines: The Req object

Maybe, try using a map %{"content-type" => "text/html"}

Although I don’t have much experience with bare cowboy…

Also, I don’t remember if we need to use single quotes for string or not (for the Erlang side)…

Good luck…

Edit: According to the above link, the maps fields is expected to be “binaries” and according to here Erlang/Elixir Syntax: A Crash Course - The Elixir programming language using double quotes on the Elixir side is enough…

1 Like

Ah… ah yes!, moving to a map for headers solves that error. I tried that early but apparently got stuck on another error after without realizing, and never went back to try that. Thanks for suggesting it.

nine nines docs show this:

init(Req0=#{method := <<"GET">>}, State) ->
    Req = cowboy_req:reply(200, #{
        <<"content-type">> => <<"text/plain">>
    }, <<"Hello world!">>, Req0),
    {ok, Req, State};

In hindsight I just had to search to confirm #{} syntax in Erlang means a map in Elixir, d’oh. And I misunderstood what comes back from cowboy_req.reply, now that I can navigate Erlang code a tiny bit I can see it’s init that returns an ok-tuple, not .reply itself.

Anyway, everything works now, thanks for the assist @Sanjibukai!

Updated code

defmodule CowboyExample.Application do
use Application

def start(_type, args) do
dispatch = :cowboy_router.compile([{:
, [{“/”, CowboyExample.HelloHandler, }]}])

{:ok, _} =
    [{:port, 8080}],
    %{env: %{dispatch: dispatch}}

IO.puts("Cowboy server started on port 8080")

Supervisor.start_link([], strategy: :one_for_one, name: CowboyExample.Supervisor)


defmodule CowboyExample.HelloHandler do
def init(req, _opts) do
req = :cowboy_req.reply(200, %{“content-type” => “text/html”}, “

Hello World!

”, req)
{:ok, req, :nostate}