** (KeyError) key :resp_headers not found (even though the key definitely exists

Hi folks,

I’m going through Pragmatic Studio’s Elixir course, and I’m stuck on a section where we take “content_type” and make it a key on a resp_headers atom inside the overall struct. The struct looks like this:

defmodule Servy.Conv do
    defstruct [
        method: "", 
        path: "", 
        resp_body: "",
        status: nil,
        params: %{},
        headers: %{},
        resp_headers: %{"Content-Type" => "text/html"}
    ]

I am attempting to access that resp_headers atom in this function:

def format_response(%Conv{} = conv) do
        """
        HTTP/1.1 #{Conv.full_status(conv)}
        Content-Type: #{conv.resp_headers["Content-Type"]}\r
        Content-Length: #{byte_size(conv.resp_body)}

        #{conv.resp_body}
        """
    end

However, when I run mix compile, I get the following error:

== Compilation error in file lib/servy/handler.ex ==
** (KeyError) key :resp_headers not found in: %{__struct__: Servy.Conv, content_type: "text/html", headers: %{"Accept" => "*/*", "Host" => "example.com", "User-Agent" => "ExampleBrowser/1.0"}, method: "GET", params: %{}, path: "/api/bears", resp_body: "", status: nil}
    lib/servy/api/bear_controller.ex:8: Servy.Api.BearController.index/1
    lib/servy/handler.ex:19: Servy.Handler.handle/1
    lib/servy/handler.ex:105: (file)
    (elixir 1.12.3) lib/kernel/parallel_compiler.ex:319: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

What am I missing? It seems clear to me that the Servy.Conv struct does indeed have a resp_headers atom that defaults to a map with the default value %{"Content-Type" => "text/html"}. Yet when trying to compile, you can see in the print out that :resp_headers doesn’t exist among the atoms that are part of that struct.

Can anyone explain what’s going on or why the compiler doesn’t seem to be picking up that Servy.Conv now has a new atom called resp_headers? Thanks in advance for your help!

Where the inspection of your struct chooses to display it as %{__struct__: Servy.Conv instead of %Servy.Conv{, it’s recognizing your struct has the wrong set of keys for a %Servy.Conv{} struct. If you look through the map printed in the error, there is no :resp_headers key.

Elixir structs are maps and will let you do map things to them, even if it doesn’t maintain the integrity of your struct. Does your code somewhere do a Map.delete(conv, :resp_headers) (or iterate over fields or try to turn an existing map into a conv struct or something where you aren’t treating your conv as a struct)?

1 Like

Thanks for the response! I could not find anywhere I was altering the available “properties” of the struct, but I changed the field back to be a simple string field instead of a map, and I’ve got things compiling again. I will revisit the issue later if need be and will post a solution if I find it :slight_smile: