Set up
-------
phoenix: 1.7.10
elixir 1.16.0-rc.1-otp-26
erlang 26.1.2
I’m working on a basic umbrella app in “Phoenix in Action 1.4”. After finishing chapter 7, where I set up the database, I noticed some output in the terminal window where I started the server (see below). Besides the error in the title of my post, buried in the middle of the output is also this:
(Protocol.UndefinedError) protocol String.Chars not implemented for %Postgrex.Query{…
Edit: I only get those errors when I start the server in the directory:
auction_umbrella/apps/auction_web $ mix phx.server
If I start the server here:
auction_umbrella$ mix phx.server
I don’t get those errors.
Full error output:
1:10:29.869 request_id=F6Sh9FdVahcsEh0AAALh
[error] an exception was raised logging %DBConnection.LogEntry{call: :execute, query: %Postgrex.Query{ref: reference<0.4235129421.45875201.249523>, name: “ecto_674”, statement: “SELECT i0."id", i0."title", i0."description", i0."ends_at", i0."inserted_at", i0."updated_at" FROM "items" AS i0”, param_oids: , param_formats: , param_types: , columns: [“id”, “title”, “description”, “ends_at”, “inserted_at”, “updated_at”], result_oids: [20, 1043, 1043, 1114, 1114, 1114], result_formats: [:binary, :binary, :binary, :binary, :binary, :binary], result_types: [Postgrex.Extensions.Int8, Postgrex.Extensions.Raw, Postgrex.Extensions.Raw, Postgrex.Extensions.Timestamp, Postgrex.Extensions.Timestamp, Postgrex.Extensions.Timestamp], types: {Postgrex.DefaultTypes, reference<0.4235129421.46006273.115603>}, cache: :reference}, params: , result: {:ok, %Postgrex.Query{ref: reference<0.4235129421.45875201.249523>, name: “ecto_674”, statement: “SELECT i0."id", i0."title", i0."description", i0."ends_at", i0."inserted_at", i0."updated_at" FROM "items" AS i0”, param_oids: , param_formats: , param_types: , columns: [“id”, “title”, “description”, “ends_at”, “inserted_at”, “updated_at”], result_oids: [20, 1043, 1043, 1114, 1114, 1114], result_formats: [:binary, :binary, :binary, :binary, :binary, :binary], result_types: [Postgrex.Extensions.Int8, Postgrex.Extensions.Raw, Postgrex.Extensions.Raw, Postgrex.Extensions.Timestamp, Postgrex.Extensions.Timestamp, Postgrex.Extensions.Timestamp], types: {Postgrex.DefaultTypes, reference<0.4235129421.46006273.115603>}, cache: :reference}, %Postgrex.Result{command: :select, columns: [“id”, “title”, “description”, “ends_at”, “inserted_at”, “updated_at”], rows: [[2, “My super item”, “A tasty item to please”, ~N[2024-02-22 11:43:39.000000], ~N[2023-12-27 01:39:34.000000], ~N[2023-12-27 01:39:34.000000]], [3, “U2 - Achtung Baby on CD”, “The sound of 4 men chopping down The Joshua Tree”, ~N[2024-02-24 14:30:00.000000], ~N[2023-12-27 01:44:18.000000], ~N[2023-12-27 01:44:18.000000]], [5, “hello”, “world”, ~N[2019-02-22 11:43:39.000000], ~N[2023-12-27 01:57:58.000000], ~N[2023-12-27 01:57:58.000000]], [1, “Old Yeller”, “Computer games and thermonuclear war”, ~N[2019-02-22 11:43:39.000000], ~N[2023-12-27 01:27:51.000000], ~N[2023-12-27 08:08:32.000000]]], num_rows: 4, connection_id: 63442, messages: }}, pool_time: 158833, connection_time: 4078858, decode_time: 19917, idle_time: 1817420099}: ** (Protocol.UndefinedError) protocol String.Chars not implemented for %Postgrex.Query{ref: reference<0.4235129421.45875201.249523>, name: “ecto_674”, statement: “SELECT i0."id", i0."title", i0."description", i0."ends_at", i0."inserted_at", i0."updated_at" FROM "items" AS i0”, param_oids: , param_formats: , param_types: , columns: [“id”, “title”, “description”, “ends_at”, “inserted_at”, “updated_at”], result_oids: [20, 1043, 1043, 1114, 1114, 1114], result_formats: [:binary, :binary, :binary, :binary, :binary, :binary], result_types: [Postgrex.Extensions.Int8, Postgrex.Extensions.Raw, Postgrex.Extensions.Raw, Postgrex.Extensions.Timestamp, Postgrex.Extensions.Timestamp, Postgrex.Extensions.Timestamp], types: {Postgrex.DefaultTypes, reference<0.4235129421.46006273.115603>}, cache: :reference} of type Postgrex.Query (a struct). This protocol is implemented for the following type(s): Atom, BitString, Date, DateTime, Float, Integer, List, NaiveDateTime, Phoenix.LiveComponent.CID, Time, URI, Version, Version.Requirement
(elixir 1.16.0-rc.1) lib/string/chars.ex:3: String.Chars.impl_for!/1
(elixir 1.16.0-rc.1) lib/string/chars.ex:22: String.Chars.to_string/1
(ecto_sql 3.11.1) lib/ecto/adapters/sql.ex:1207: Ecto.Adapters.SQL.log/4
(db_connection 2.6.0) lib/db_connection.ex:1658: DBConnection.log/5
(ecto_sql 3.11.1) lib/ecto/adapters/postgres/connection.ex:133: Ecto.Adapters.Postgres.Connection.execute/4
(ecto_sql 3.11.1) lib/ecto/adapters/sql.ex:996: Ecto.Adapters.SQL.execute!/5
(ecto_sql 3.11.1) lib/ecto/adapters/sql.ex:952: Ecto.Adapters.SQL.execute/6
(ecto 3.11.1) lib/ecto/repo/queryable.ex:232: Ecto.Repo.Queryable.execute/401:10:29.869 request_id=F6Sh9FdVahcsEh0AAALh [info] Sent 200 in 7ms
There are two apps in the umbrella project: auction and auction_web. Here are their mix.exs files:
auction_web:
defmodule AuctionWeb.MixProject do
use Mix.Project
def project do
[
app: :auction_web,
version: "0.1.0",
build_path: "../../_build",
config_path: "../../config/config.exs",
deps_path: "../../deps",
lockfile: "../../mix.lock",
elixir: "~> 1.14",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps()
]
end
# Configuration for the OTP application.
#
# Type `mix help compile.app` for more information.
def application do
[
mod: {AuctionWeb.Application, []},
extra_applications: [:logger, :runtime_tools]
]
end
# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
# Specifies your project dependencies.
#
# Type `mix help deps` for examples and options.
defp deps do
[
{:phoenix, "~> 1.7.10"},
{:phoenix_html, "~> 3.3"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 0.20.1"},
{:floki, ">= 0.30.0", only: :test},
{:phoenix_live_dashboard, "~> 0.8.2"},
{:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
{:tailwind, "~> 0.2.0", runtime: Mix.env() == :dev},
{:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"},
{:gettext, "~> 0.20"},
{:jason, "~> 1.2"},
{:plug_cowboy, "~> 2.5"},
# Stuff I added:
{:auction, in_umbrella: true},
{:phoenix_ecto, "~> 4.4.3"}
]
end
# Aliases are shortcuts or tasks specific to the current project.
#
# See the documentation for `Mix` for more info on aliases.
defp aliases do
[
setup: ["deps.get", "assets.setup", "assets.build"],
"assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"],
"assets.build": ["tailwind default", "esbuild default"],
"assets.deploy": ["tailwind default --minify", "esbuild default --minify", "phx.digest"]
]
end
end
auction:
defmodule Auction.MixProject do
use Mix.Project
def project do
[
app: :auction,
version: "0.1.0",
build_path: "../../_build",
config_path: "../../config/config.exs",
deps_path: "../../deps",
lockfile: "../../mix.lock",
elixir: "~> 1.16-rc",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger],
mod: {Auction.Application, []}
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
# {:sibling_app_in_umbrella, in_umbrella: true}
{:ecto_sql, "~> 3.11.1"},
{:postgrex, "~> 0.17.4"}
]
end
end
The only config file is auction_umbrella/config/config.exs:
# This file is responsible for configuring your umbrella
# and **all applications** and their dependencies with the
# help of the Config module.
#
# Note that all applications in your umbrella share the
# same configuration and dependencies, which is why they
# all use the same configuration file. If you want different
# configurations or dependencies per app, it is best to
# move said applications out of the umbrella.
import Config
config :auction, ecto_repos: [Auction.Repo]
config :auction, Auction.Repo,
database: "auction",
username: "7stud",
password: "",
hostname: "localhost",
port: "5432"
config :auction_web,
generators: [context_app: false]
# Configures the endpoint
config :auction_web, AuctionWeb.Endpoint,
url: [host: "localhost"],
adapter: Phoenix.Endpoint.Cowboy2Adapter,
render_errors: [
formats: [html: AuctionWeb.ErrorHTML, json: AuctionWeb.ErrorJSON],
layout: false
],
pubsub_server: AuctionWeb.PubSub,
live_view: [signing_salt: "QtLBNvjp"]
# Configure esbuild (the version is required)
config :esbuild,
version: "0.17.11",
default: [
args:
~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
cd: Path.expand("../apps/auction_web/assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
# Configure tailwind (the version is required)
config :tailwind,
version: "3.3.2",
default: [
args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/static/assets/app.css
),
cd: Path.expand("../apps/auction_web/assets", __DIR__)
]
# Sample configuration:
#
# config :logger, :console,
# level: :info,
# format: "$date $time [$level] $metadata$message\n",
# metadata: [:user_id]
#
import Config
# Configures Elixir's Logger
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{config_env()}.exs"






















