Argument error / :erlang.iolist_size/1 when querying

Hi!

I have made a custom query with the query builder to fetch some posts, and I get an error page upon trying to use it in a controller.

error page

The query is very straight forward and I have similar things working in my code base already.

The query is as follows:

query =
      from p in Post,
        select: p,
        where: p.published? == true

    Repo.query!(query)

I have tried removing select and where, but the same thing happens then, as well.

Here is the schema:

  schema "news_posts" do
    field :title, :string
    field :markdown_body, :string
    field :html_body, :string
    field :published?, :boolean, source: :is_published, default: false

    belongs_to :user, User

    timestamps()
  end

Any ideas, guys?

It looks like you are trying to show the query itself, not the results. You’ll see in your error ["", 0, "#<Ecto.Query....", 0, ...]. This structure is called an iolist which is very efficient for Elixir/Erlang/Phoenix to send as output since it doesn’t have to build a consolidated string.

However it relies on the idea that everything in the list can be converted to a string. And an #<Ecto.Query...> struct cannot be directly converted.

Without additional code its hard to know exactly, but this would be my preliminary diagnosis based on the error message.

I suggest trying your query in iex first.

Thanks for the answer!

I tried running it in iex, and I seem to get the same problem here.
The query is successfully built but upon calling it I receive the following error:

[error] an exception was raised logging %DBConnection.LogEntry{call: :prepare_execute, connection_time: 40561270, decode_time: nil, params: [], pool_time: 242862, query: %Postgrex.Query{cache: :reference, columns: nil, name: "", param_formats: nil, param_oids: nil, param_types: nil, ref: nil, result_formats: nil, result_oids: nil, result_types: nil, statement: #Ecto.Query<from p0 in Sombra.News.Post, where: p0.published? == true, select: p0>, types: nil}, result: {:error, %DBConnection.ConnectionError{message: "an exception was raised: ** (ArgumentError) argument error\n    :erlang.iolist_size([\"\", 0, #Ecto.Query<from p0 in Sombra.News.Post, where: p0.published? == true, select: p0>, 0, <<0, 0>>, \"\"])\n    (postgrex) lib/postgrex/messages.ex:227: Postgrex.Messages.encode_msg/1\n    (postgrex) lib/postgrex/protocol.ex:2774: anonymous fn/2 in Postgrex.Protocol.msg_send/3\n    (elixir) lib/enum.ex:1948: Enum.\"-reduce/3-lists^foldl/2-0-\"/3\n    (postgrex) lib/postgrex/protocol.ex:2774: Postgrex.Protocol.msg_send/3\n    (postgrex) lib/postgrex/protocol.ex:1021: Postgrex.Protocol.parse_describe_flush/3\n    (db_connection) lib/db_connection/holder.ex:277: DBConnection.Holder.holder_apply/4\n    (db_connection) lib/db_connection.ex:1240: DBConnection.prepare/4\n    (db_connection) lib/db_connection.ex:1233: DBConnection.run_prepare/4\n    (db_connection) lib/db_connection.ex:1245: DBConnection.run_prepare_execute/5\n    (db_connection) lib/db_connection.ex:1342: DBConnection.run/6\n    (db_connection) lib/db_connection.ex:540: DBConnection.parsed_prepare_execute/5\n    (db_connection) lib/db_connection.ex:533: DBConnection.prepare_execute/4\n    (postgrex) lib/postgrex.ex:217: Postgrex.query_prepare_execute/4\n    (ecto_sql) lib/ecto/adapters/sql.ex:292: Ecto.Adapters.SQL.query!/4\n    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6\n    (elixir) src/elixir.erl:275: :elixir.eval_forms/4\n    (iex) lib/iex/evaluator.ex:257: IEx.Evaluator.handle_eval/5\n    (iex) lib/iex/evaluator.ex:237: IEx.Evaluator.do_eval/3\n    (iex) lib/iex/evaluator.ex:215: IEx.Evaluator.eval/3\n"}}}: ** (ArgumentError) argument error
    :erlang.iolist_to_binary(#Ecto.Query<from p0 in Sombra.News.Post, where: p0.published? == true, select: p0>)
    (postgrex) lib/postgrex/query.ex:99: String.Chars.Postgrex.Query.to_string/1
    (ecto_sql) lib/ecto/adapters/sql.ex:772: Ecto.Adapters.SQL.log/4
    (db_connection) lib/db_connection.ex:1377: DBConnection.log/5
    (postgrex) lib/postgrex.ex:217: Postgrex.query_prepare_execute/4
    (ecto_sql) lib/ecto/adapters/sql.ex:292: Ecto.Adapters.SQL.query!/4
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir) src/elixir.erl:275: :elixir.eval_forms/4
    (iex) lib/iex/evaluator.ex:257: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:237: IEx.Evaluator.do_eval/3
    (iex) lib/iex/evaluator.ex:215: IEx.Evaluator.eval/3
    (iex) lib/iex/evaluator.ex:103: IEx.Evaluator.loop/1
    (iex) lib/iex/evaluator.ex:27: IEx.Evaluator.init/4
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

** (ArgumentError) argument error
    :erlang.iolist_size(["", 0, #Ecto.Query<from p0 in Sombra.News.Post, where: p0.published? == true, select: p0>, 0, <<0, 0>>, ""])
    (postgrex) lib/postgrex/messages.ex:227: Postgrex.Messages.encode_msg/1 
    (postgrex) lib/postgrex/protocol.ex:2774: anonymous fn/2 in Postgrex.Protocol.msg_send/3
    (elixir) lib/enum.ex:1948: Enum."-reduce/3-lists^foldl/2-0-"/3
    (postgrex) lib/postgrex/protocol.ex:2774: Postgrex.Protocol.msg_send/3
    (postgrex) lib/postgrex/protocol.ex:1021: Postgrex.Protocol.parse_describe_flush/3
    (db_connection) lib/db_connection/holder.ex:277: DBConnection.Holder.holder_apply/4
    (db_connection) lib/db_connection.ex:1240: DBConnection.prepare/4
    (db_connection) lib/db_connection.ex:1233: DBConnection.run_prepare/4
    (db_connection) lib/db_connection.ex:1245: DBConnection.run_prepare_execute/5
    (db_connection) lib/db_connection.ex:1342: DBConnection.run/6
    (db_connection) lib/db_connection.ex:540: DBConnection.parsed_prepare_execute/5
    (db_connection) lib/db_connection.ex:533: DBConnection.prepare_execute/4
    (postgrex) lib/postgrex.ex:217: Postgrex.query_prepare_execute/4
    (ecto_sql) lib/ecto/adapters/sql.ex:292: Ecto.Adapters.SQL.query!/4
iex(10)> [error] GenServer #PID<0.370.0> terminating
** (DBConnection.ConnectionError) client #PID<0.547.0> stopped: ** (ArgumentError) argument error
    :erlang.iolist_size(["", 0, #Ecto.Query<from p0 in Sombra.News.Post, where: p0.published? == true, select: p0>, 0, <<0, 0>>, ""])
    (postgrex) lib/postgrex/messages.ex:227: Postgrex.Messages.encode_msg/1
    (postgrex) lib/postgrex/protocol.ex:2774: anonymous fn/2 in Postgrex.Protocol.msg_send/3
    (elixir) lib/enum.ex:1948: Enum."-reduce/3-lists^foldl/2-0-"/3
    (postgrex) lib/postgrex/protocol.ex:2774: Postgrex.Protocol.msg_send/3
    (postgrex) lib/postgrex/protocol.ex:1021: Postgrex.Protocol.parse_describe_flush/3
    (db_connection) lib/db_connection/holder.ex:277: DBConnection.Holder.holder_apply/4
    (db_connection) lib/db_connection.ex:1240: DBConnection.prepare/4
    (db_connection) lib/db_connection.ex:1233: DBConnection.run_prepare/4
    (db_connection) lib/db_connection.ex:1245: DBConnection.run_prepare_execute/5
    (db_connection) lib/db_connection.ex:1342: DBConnection.run/6
    (db_connection) lib/db_connection.ex:540: DBConnection.parsed_prepare_execute/5
    (db_connection) lib/db_connection.ex:533: DBConnection.prepare_execute/4
    (postgrex) lib/postgrex.ex:217: Postgrex.query_prepare_execute/4
    (ecto_sql) lib/ecto/adapters/sql.ex:292: Ecto.Adapters.SQL.query!/4
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir) src/elixir.erl:275: :elixir.eval_forms/4
    (iex) lib/iex/evaluator.ex:257: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:237: IEx.Evaluator.do_eval/3
    (iex) lib/iex/evaluator.ex:215: IEx.Evaluator.eval/3

    (db_connection) lib/db_connection/connection.ex:162: DBConnection.Connection.handle_cast/2
    (connection) lib/connection.ex:810: Connection.handle_async/3 
    (stdlib) gen_server.erl:637: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:711: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:259: :proc_lib.wake_up/3
Last message: {:"$gen_cast", {:stop, #Reference<0.3943072288.1394475010.34145>, %DBConnection.ConnectionError{message: "client #PID<0.547.0> stopped: ** (ArgumentError) argument error\n    :erlang.iolist_size([\"\", 0, #Ecto.Query<from p0 in Sombra.News.Post, where: p0.published? == true, select: p0>, 0, <<0, 0>>, \"\"])\n    (postgrex) lib/postgrex/messages.ex:227: Postgrex.Messages.encode_msg/1\n    (postgrex) lib/postgrex/protocol.ex:2774: anonymous fn/2 in Postgrex.Protocol.msg_send/3\n    (elixir) lib/enum.ex:1948: Enum.\"-reduce/3-lists^foldl/2-0-\"/3\n    (postgrex) lib/postgrex/protocol.ex:2774: Postgrex.Protocol.msg_send/3\n    (postgrex) lib/postgrex/protocol.ex:1021: Postgrex.Protocol.parse_describe_flush/3\n    (db_connection) lib/db_connection/holder.ex:277: DBConnection.Holder.holder_apply/4\n    (db_connection) lib/db_connection.ex:1240: DBConnection.prepare/4\n    (db_connection) lib/db_connection.ex:1233: DBConnection.run_prepare/4\n    (db_connection) lib/db_connection.ex:1245: DBConnection.run_prepare_execute/5\n    (db_connection) lib/db_connection.ex:1342: DBConnection.run/6\n    (db_connection) lib/db_connection.ex:540: DBConnection.parsed_prepare_execute/5\n    (db_connection) lib/db_connection.ex:533: DBConnection.prepare_execute/4\n    (postgrex) lib/postgrex.ex:217: Postgrex.query_prepare_execute/4\n    (ecto_sql) lib/ecto/adapters/sql.ex:292: Ecto.Adapters.SQL.query!/4\n    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6\n    (elixir) src/elixir.erl:275: :elixir.eval_forms/4\n    (iex) lib/iex/evaluator.ex:257: IEx.Evaluator.handle_eval/5\n    (iex) lib/iex/evaluator.ex:237: IEx.Evaluator.do_eval/3\n    (iex) lib/iex/evaluator.ex:215: IEx.Evaluator.eval/3\n"}, %Postgrex.Protocol{buffer: "", connection_id: 13921, connection_key: 726524142, disconnect_on_error_codes: [], null: nil, parameters: #Reference<0.3943072288.1394343937.29568>, peer: {{127, 0, 0, 1}, 5432}, postgres: :idle, queries: #Reference<0.3943072288.1394475009.29554>, sock: {:gen_tcp, #Port<0.12>}, timeout: 15000, transactions: :naive, types: {Postgrex.DefaultTypes, #Reference<0.3943072288.1394475012.29604>}}}}
State: {Postgrex.Protocol, %Postgrex.Protocol{buffer: "", connection_id: 13921, connection_key: 726524142, disconnect_on_error_codes: [], null: nil, parameters: #Reference<0.3943072288.1394343937.29568>, peer: {{127, 0, 0, 1}, 5432}, postgres: :idle, queries: #Reference<0.3943072288.1394475009.29554>, sock: {:gen_tcp, #Port<0.12>}, timeout: 15000, transactions: :naive, types: {Postgrex.DefaultTypes, #Reference<0.3943072288.1394475012.29604>}}}

And the code in the first post, with the query and the Repo.query! call is the entire body of a function which is then called in a page controller. It is completely isolated from anything non-phoenix, as far as I can see…

You’ll need to show more code, it isn’t possible to diagnose with the couple of snippets you’ve provided.

Ok, can do!

What code would you, specifically, need?
As I said, this is just the body of a function:

defmodule Sombra.News do
  [...]
  def list_published_posts() do
    query =
        from p in Post,
          select: p,
          where: p.published? == true

      Repo.query!(query)
  end
  [...]
end

This function is then called inside a normal page controller, like this:

defmodule SombraWeb.PageController do
  [...]
  def index(conn, _params) do
    news_posts = News.list_published_posts()

    render(conn, "index.html", news_posts: news_posts)
  end
  [...]
end

I also noticed that another, similar function, got the same issue now. This is exactly the same, only it accessed another table and checked another bool…

I have one other such function, based on query builder, which works. Very strange stuff…

Repo.query! takes a string query, not a query struct. I think you should be calling Repo.all or Repo.one. Here’s an example:

iex> import Ecto.Query                                       
Ecto.Query

iex> alias Money.SQL.Repo                                    
Money.SQL.Repo

# Repo.query! takes a String argument, not a query struct
# as in this example
iex> Repo.query! "select * from organizations"
%Postgrex.Result{
  columns: ["id", "name", "employee_count", "payroll", "inserted_at",
   "updated_at"],
  command: :select,
  connection_id: 53491,
  messages: [],
  num_rows: 0,
  rows: []
}
iex> q = from o in Organization                              
#Ecto.Query<from o0 in Organization>

# It will fail noisily if a query struct is passed
# This could be a better error for sure
iex> Repo.query! q                           
12:15:41.911 [error] an exception was raised logging %DBConnection.LogEntry{call: ...

# All ok with Repo.all and a query struct
iex> Repo.all q 
[...]
2 Likes

That makes sense, and it worked!

I was under the false assumption that query! worked, as the bug didn’t surface in that other function, until after this one.

Thanks a lot for the help!