I’ve recently started a new Phoenix project using Elixir 1.11, Phoenix 1.5 and Ecto 3.5.
Everything runs smoothly but there is a recurrent warning in ElixirLS which I can not fix. The warning says:
the Inspect protocol has already been consolidated, an implementation for MyApp.User has no effect. If you want to implement protocols after compilation or during tests, check the “Consolidation” section in the Protocol module documentation
The warning is highlighted in the Ecto schema declaration:
The thing is: the module does not implement the Inspect protocol. I know I can disable protocol consolidation in development to make this warning disappear, but I would like to know what is causing it. It only happens in this schema and not in the resto of Ecto schemas I have implemented.
EDIT
I’ve dived into the Ecto.Schema.schema() code and found this code which I belive is causing the warning:
if redacted_fields != [] and not List.keymember?(@derive, Inspect, 0) and
@ecto_derive_inspect_for_redacted_fields do
@derive {Inspect, except: @ecto_redact_fields}
end
My schema has a field :password, :string, virtual: true, redact: true which triggers this code and derives the Inspect protocol for my schema.
So, now that I know where this comes from. Is there a way to fix this warning? Should I report it as a bug in Ecto?
Well, I didn’t change any configuration related to this. So it seems to be the default behaviour for Elixir projects.
ElixirLS recompiles the project when saving updated files and it is the one triggering this warnings. Running mix compile manually does not show any warning.
The user schema generated by phx_gen_auth also produces this warning.
Elixir 1.11.1 (compiled with Erlang/OTP 23)
@derive {Inspect, except: [:password]}
schema "users" do
field :email, :string
field :password, :string, virtual: true
field :hashed_password, :string
field :confirmed_at, :naive_datetime
timestamps()
end
This is a good question because digging into it made me find a potential workaround. (edit: it didn’t work )
Reading through the Protocol docs, it mentions that consolidation isn’t used in development (due to code reloading), but consolidation still happens during compilation. We can turn that off by telling it to not consolidate in dev:
# mix.exs
def project do
...
consolidate_protocols: Mix.env() != :dev
...
end
I am hoping that this will cause the warning to go away with no ill effects, since consolidation isn’t used in development anyways.
edit:
Within minutes the warning appears again. Apparently, disabling consolidation didn’t actually prevent it from consolidating.
In order to speed up dispatching in production environments, where all implementations are known up-front, Elixir provides a feature called protocol consolidation . Consolidation directly links protocols to their implementations in a way that invoking a function from a consolidated protocol is equivalent to invoking two remote functions.
The bug has been resolved in Phoenix, which does not report the warning anymore. ElixirLS is not fixed yet and keeps showing the warning just like before.
For what it’s worth, when using the bare phx.gen.auth generator, which puts the @derive {Inspect, except: [:password]} line on the user schema, I was getting the consolidation warning in ElixirLS but after upgrading to the latest version of Phoenix (and removing the .elixir_ls folder and letting it rebuild) I’m not seeing the warnings anymore.
Well, this is not what you’re supposed to do if you still want to use ElixirLS.
As far as I know there’s already a fix in Phoenix side in master (but not yet released).
But if you don’t want to use master and that you’re bothered by the warning (like I was) you can simply add this in your mix.exs file:
def project do
[
..
consolidate_protocols: Mix.env() != :test,
..
]
end
schema "sip_accounts" do
field :password, :string, redact: true
field :phone_number, :string
field :sip_proxy, :string
field :username, :string, redact: true
and that is giving:
warning: the Inspect protocol has already been consolidated, an implementation for ResiSwitch.SIPAccounts.SIPAccount has no effect. If you want to implement protocols after compilation or during tests, check the "Consolidation" section in the Protocol module documentation
lib/resi_switch/sip_accounts/sip_account.ex:7
yet, my user schema from phx.gen.auth isn’t giving a warning, which has the same kind of redact line:
schema "users" do
field :email, :string
field :password, :string, virtual: true, redact: true
field :hashed_password, :string, redact: true
field :confirmed_at, :naive_datetime
I’m running into the same issue with a simple (demo) Ash Framework project. As soon as I added more than the basic persistence, started seeing:
warning: the Inspect protocol has already been consolidated, an implementation for Helpdesk.Support.Ticket has no effect. If you want to implement protocols after compilation or during tests, check the "Consolidation" section in the Protocol module documentation
lib/helpdesk/support/resources/ticket.ex:1
The code is pretty simple:
defmodule Helpdesk.Support.Ticket do
use Ash.Resource
actions do
defaults [:create, :read, :update, :destroy]
create :open do
accept [:subject]
end
end
attributes do
uuid_primary_key :id
attribute :subject, :string do
allow_nil? false
end
attribute :status, :atom do
constraints [one_of: [:open, :closed]]
default :open
allow_nil? false
end
end
end