Getting Protocol.UndefinedError when try to insert with ecto

Hello everyone, i’m new with Elixir

and i’m getting error Protocol.UndefinedError, but i don’t understand what’s mean.

Many thanks.

My schema:

defmodule Worker.Schema.Credit do
    use Ecto.Schema

    @primary_key {:id, :binary_id, autogenerate: false}

    schema "credit" do
        field :used, :boolean
        field :start_date, :date
        field :finish_date, :date
        field :user_id, :binary_id
        field :created_at, :naive_datetime
        field :updated_at, :naive_datetime
    end
end

My insert code:

      initial_date = Date.utc_today
      end_date = initial_date |> Date.add(plan.credits_periodicity+val)
      
      credit = %Worker.Schema.Credit{
        id: Ecto.UUID.generate(),
        used: false,
        start_date: initial_date,
        finish_date: end_date,
        user_id: user.id,
        created_at: NaiveDateTime.utc_now(),
        updated_at: NaiveDateTime.utc_now()
      }

      IO.puts credit

      case Worker.Repo.insert credit do
        {:ok, struct}       -> # Inserted with success
        {:error, changeset} -> # Something went wrong
      end

Trace of the error:

05:08:34.170 [error] GenServer #PID<0.982.0> terminating
** (Protocol.UndefinedError) protocol String.Chars not implemented for %Worker.Schema.Credit{__meta__: #Ecto.Schema.Metadata<:built, "credit">, created_at: ~N[2019-06-26 05:08:34.167743], finish_date: ~D[2019-06-27], id: "778a710d-07d2-4b33-881a-ab910613171f", start_date: ~D[2019-06-26], updated_at: ~N[2019-06-26 05:08:34.167753], used: false, user_id: "844e9ac6-3e39-45d1-bf57-84fc3395a479"}. This protocol is implemented for: Postgrex.Copy, Postgrex.Query, Decimal, Time, Date, Float, List, URI, Integer, Atom, Version, DateTime, BitString, NaiveDateTime, Version.Requirement
    (elixir) /usr/local/src/elixir/lib/elixir/lib/string/chars.ex:3: String.Chars.impl_for!/1
    (elixir) /usr/local/src/elixir/lib/elixir/lib/string/chars.ex:22: String.Chars.to_string/1
    (elixir) lib/io.ex:553: IO.puts/2
    (worker) lib/worker/cli.ex:31: anonymous fn/4 in Worker.CLI.consume/4
    (elixir) lib/enum.ex:3003: Enum.reduce_range_inc/4
    (worker) lib/worker/cli.ex:18: Worker.CLI.consume/4
    (worker) lib/worker/queue/consumer.ex:42: Worker.Queue.Consumer.handle_info/2
    (stdlib) gen_server.erl:637: :gen_server.try_dispatch/4
Last message: {:basic_deliver, "{\"userId\": \"844e9ac6-3e39-45d1-bf57-84fc3395a479\", \"planId\": \"af6253b4-f4bb-4f77-b731-ba7502a39d92\"}", %{app_id: :undefined, cluster_id: :undefined, consumer_tag: "amq.ctag-ohCpSBfpW8Lee9jlw1QgGQ", content_encoding: :undefined, content_type: :undefined, correlation_id: :undefined, delivery_tag: 1, exchange: "", expiration: :undefined, headers: [], message_id: :undefined, persistent: false, priority: :undefined, redelivered: false, reply_to: :undefined, routing_key: "credits", timestamp: :undefined, type: :undefined, user_id: :undefined}}
State: %AMQP.Channel{conn: %AMQP.Connection{pid: #PID<0.985.0>}, pid: #PID<0.994.0>}

05:08:34.179 [error] GenServer Worker.Repo terminating
** (Protocol.UndefinedError) protocol String.Chars not implemented for %Worker.Schema.Credit{__meta__: #Ecto.Schema.Metadata<:built, "credit">, created_at: ~N[2019-06-26 05:08:34.167743], finish_date: ~D[2019-06-27], id: "778a710d-07d2-4b33-881a-ab910613171f", start_date: ~D[2019-06-26], updated_at: ~N[2019-06-26 05:08:34.167753], used: false, user_id: "844e9ac6-3e39-45d1-bf57-84fc3395a479"}. This protocol is implemented for: Postgrex.Copy, Postgrex.Query, Decimal, Time, Date, Float, List, URI, Integer, Atom, Version, DateTime, BitString, NaiveDateTime, Version.Requirement
    (elixir) /usr/local/src/elixir/lib/elixir/lib/string/chars.ex:3: String.Chars.impl_for!/1
    (elixir) /usr/local/src/elixir/lib/elixir/lib/string/chars.ex:22: String.Chars.to_string/1
    (elixir) lib/io.ex:553: IO.puts/2
    (worker) lib/worker/cli.ex:31: anonymous fn/4 in Worker.CLI.consume/4
    (elixir) lib/enum.ex:3003: Enum.reduce_range_inc/4
    (worker) lib/worker/cli.ex:18: Worker.CLI.consume/4
    (worker) lib/worker/queue/consumer.ex:42: Worker.Queue.Consumer.handle_info/2
    (stdlib) gen_server.erl:637: :gen_server.try_dispatch/4
Last message: {:EXIT, #PID<0.955.0>, {%Protocol.UndefinedError{description: "", protocol: String.Chars, value: %Worker.Schema.Credit{__meta__: #Ecto.Schema.Metadata<:built, "credit">, created_at: ~N[2019-06-26 05:08:34.167743], finish_date: ~D[2019-06-27], id: "778a710d-07d2-4b33-881a-ab910613171f", start_date: ~D[2019-06-26], updated_at: ~N[2019-06-26 05:08:34.167753], used: false, user_id: "844e9ac6-3e39-45d1-bf57-84fc3395a479"}}, [{String.Chars, :impl_for!, 1, [file: '/usr/local/src/elixir/lib/elixir/lib/string/chars.ex', line: 3]}, {String.Chars, :to_string, 1, [file: '/usr/local/src/elixir/lib/elixir/lib/string/chars.ex', line: 22]}, {IO, :puts, 2, [file: 'lib/io.ex', line: 553]}, {Worker.CLI, :"-consume/4-fun-0-", 4, [file: 'lib/worker/cli.ex', line: 31]}, {Enum, :reduce_range_inc, 4, [file: 'lib/enum.ex', line: 3003]}, {Worker.CLI, :consume, 4, [file: 'lib/worker/cli.ex', line: 18]}, {Worker.Queue.Consumer, :handle_info, 2, [file: 'lib/worker/queue/consumer.ex', line: 42]}, {:gen_server, :try_dispatch, 4, [file: 'gen_server.erl', line: 637]}]}}
State: {:state, {:local, Worker.Repo}, :one_for_one, {[DBConnection.ConnectionPool], %{DBConnection.ConnectionPool => {:child, #PID<0.970.0>, DBConnection.ConnectionPool, {Ecto.Repo.Supervisor, :start_child, [{DBConnection.ConnectionPool, :start_link, [{Postgrex.Protocol, [types: Postgrex.DefaultTypes, port: 5432, repo: Worker.Repo, telemetry_prefix: [:worker, :repo], otp_app: :worker, timeout: 15000, pool_size: 10, database: "primepass_test", username: "primepass", password: "primepass", hostname: "dev-containers_postgres_1", pool: DBConnection.ConnectionPool]}]}, Ecto.Adapters.Postgres, #Reference<0.1881887683.3115188225.54614>, %{opts: [timeout: 15000, pool_size: 10, pool: DBConnection.ConnectionPool], sql: Ecto.Adapters.Postgres.Connection, telemetry: {Worker.Repo, :debug, [:worker, :repo, :query]}}]}, :permanent, 5000, :worker, [Ecto.Repo.Supervisor]}}}, :undefined, 0, 5, [], 0, Ecto.Repo.Supervisor, {Worker.Repo, Worker.Repo, :worker, Ecto.Adapters.Postgres, []}}
** (EXIT from #PID<0.955.0>) shell process exited with reason: an exception was raised:
    ** (Protocol.UndefinedError) protocol String.Chars not implemented for %Worker.Schema.Credit{__meta__: #Ecto.Schema.Metadata<:built, "credit">, created_at: ~N[2019-06-26 05:08:34.167743], finish_date: ~D[2019-06-27], id: "778a710d-07d2-4b33-881a-ab910613171f", start_date: ~D[2019-06-26], updated_at: ~N[2019-06-26 05:08:34.167753], used: false, user_id: "844e9ac6-3e39-45d1-bf57-84fc3395a479"}. This protocol is implemented for: Postgrex.Copy, Postgrex.Query, Decimal, Time, Date, Float, List, URI, Integer, Atom, Version, DateTime, BitString, NaiveDateTime, Version.Requirement
        (elixir) /usr/local/src/elixir/lib/elixir/lib/string/chars.ex:3: String.Chars.impl_for!/1
        (elixir) /usr/local/src/elixir/lib/elixir/lib/string/chars.ex:22: String.Chars.to_string/1
        (elixir) lib/io.ex:553: IO.puts/2
        (worker) lib/worker/cli.ex:31: anonymous fn/4 in Worker.CLI.consume/4
        (elixir) lib/enum.ex:3003: Enum.reduce_range_inc/4
        (worker) lib/worker/cli.ex:18: Worker.CLI.consume/4
        (worker) lib/worker/queue/consumer.ex:42: Worker.Queue.Consumer.handle_info/2
        (stdlib) gen_server.erl:637: :gen_server.try_dispatch/4

Hey @allanzi welcome! Any time you want to ask about an error, please post the full stack trace associated with the error.

Thank you @benwilson512 for the support. I updated message with the trace.

According to the stacktrace, the reason it’s trying to find a protocol implementation for String.Chars is that you’re calling IO.puts on your struct. This line here from the stacktrace: (elixir) lib/io.ex:553: IO.puts/2.

Basically, it doesn’t know how to print your struct. You can instead use IO.inspect(credit) or IO.puts(inspect(credit)).

3 Likes

This is the issue. You want to IO.inspect credit. IO.puts expects values that implement the String.Chars protocol, whereas IO.inspect works for anything that implements the Inspect protocol. The Inspect protocol DOES have a default implementation, whereas String.Chars does not.

4 Likes