Phoenix.Endpoint.Cowboy2Handler.init/2 is undefined

[error] Ranch protocol #PID<0.3531.0> of listener HTTP (connection #PID<0.3530.0>, stream id 1) terminated
an exception was raised:
    ** (UndefinedFunctionError) function Phoenix.Endpoint.Cowboy2Handler.init/2 is undefined (module Phoenix.Endpoint.Cowboy2Handler is not available)
        Phoenix.Endpoint.Cowboy2Handler.init(%{bindings: %{}, body_length: 0, cert: :undefined, has_body: false, headers: %{"accept-encoding" => "gzip, deflate", "accept-language" => "en-GB,en-US;q=0.9,en;q=0.8", "cache-control" => "no-cache", "connection" => "Upgrade", "cookie" => "_admin_key=SFMyNTY.g3QAAAAFbQAAAAtfY3NyZl90b2tlbm0AAAAYOWNTSzZjYmxhNTV4OWRhM3I2UXUtbWI4bQAAAAthY2NvdW50c191aXQAAAAIZAAJYXNjZW5kaW5nZAAEdHJ1ZWQAC2Fzc2lnbmVkX3RvZAADbmlsZAALY2FzZV9zdGF0dXNtAAAAAGQACW1hcmtlZF9hc20AAAAEcmVhbGQACG9yZGVyX2J5bQAAAAtuZXh0X3VwZGF0ZWQAGXJlcXVpcmVzX2F0dGVudGlvbl9zdGF0dXNtAAAAAGQAE3NlcnZpY2VfcHJvdmlkZXJfaWRkAANuaWxkAAZzdGF0dXNkAANuaWxtAAAACGNhc2VzX3VpdAAAAAhkAAhhcmNoaXZlZGQABWZhbHNlZAAJYXNjZW5kaW5nZAAEdHJ1ZWQAC2Fzc2lnbmVkX3RvbQAAAANhbGxkABZsYXN0X3N1Ym1pdHRlZF9zZWN0aW9uZAADbmlsZAAJbWFya2VkX2FzZAAEcmVhbGQAD25vdGlmaWVyX3N0YXR1c2QAA25pbGQACG9yZGVyX2J5bQAAAA1kZWNlYXNlZF9uYW1lZAAGc3RhdHVzZAADbmlsbQAAAAxjdXJyZW50X3VzZXJtAAAAEmFwb29ydkBzZXR0bGQuY2FyZW0AAAAPY3VycmVudF91c2VyX2lkbQAAACQ2ZjNmOWVkMi0yZDAwLTQ4OTAtOTY2YS1hZWQ4NzBjODc1MGQ.2-ad2raE24OdyXdcAX7EL3sfwiZIJzGDqMBpnr9EkHc", "host" => "admin.local.settld.care:5000", "origin" => "http://admin.local.settld.care:5000", "pragma" => "no-cache", "sec-websocket-extensions" => "permessage-deflate; client_max_window_bits", "sec-websocket-key" => "2WZlMphHbhK9hH0h8S6gFw==", "sec-websocket-version" => "13", "upgrade" => "websocket", "user-agent" => "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}, host: "admin.local.settld.care", host_info: :undefined, method: "GET", path: "/admin/phoenix/live_reload/socket/websocket", path_info: :undefined, peer: {{127, 0, 0, 1}, 43474}, pid: #PID<0.3530.0>, port: 5000, qs: "vsn=2.0.0", ref: HTTP, scheme: "http", sock: {{127, 0, 0, 1}, 5000}, streamid: 1, version: :"HTTP/1.1"}, {AdminWeb.Endpoint, {Phoenix.LiveReloader.Socket, :websocket}})
        (cowboy 2.10.0) /home/apoorv-2204/Documents/settld/backend/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2
        (cowboy 2.10.0) /home/apoorv-2204/Documents/settld/backend/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3
        (cowboy 2.10.0) /home/apoorv-2204/Documents/settld/backend/deps/cowboy/src/cowboy_stream_h.erl:295: :cowboy_stream_h.request_process/3
        (stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
[error] Ranch protocol #PID<0.3533.0> of listener HTTP (connection #PID<0.3532.0>, stream id 1) terminated
an exception was raised:
    ** (UndefinedFunctionError) function Phoenix.Endpoint.Cowboy2Handler.init/2 is undefined (module Phoenix.Endpoint.Cowboy2Handler is not available)
defmodule Proxy do
  alias Phoenix.LiveReloader.Socket, as: LiveReloadSocket
  alias Plug.Cowboy

  use Application

  require Logger

  @port Application.compile_env!(:proxy, :port)

  def start(_type, _args) do
    {:ok, pid} = in_phoenix?() |> children |> run_application()
    Logger.info("successfully started proxy on port #{to_port(@port)}")
    {:ok, pid}
  end

  defp run_application(children) do
    import Supervisor.Spec, warn: false

    Supervisor.start_link(
      children,
      strategy: :one_for_one,
      name: Proxy.Supervisor
    )
  end

  defp children(_start_cowboy = false), do: []

  defp children(_start_cowboy = true) do
    [
      Cowboy.child_spec(
        # since we're using manual dispatch, plug is ignored
        plug: nil,
        scheme: :http,
        options: [
          port: to_port(@port),
          dispatch: [
            {:_,
             [
               websocket_handler(
                 "/admin/live/websocket",
                 AdminWeb.Endpoint,
                 {Phoenix.LiveView.Socket, :websocket}
               ),
               websocket_handler(
                 "/admin/phoenix/live_reload/socket/websocket",
                 AdminWeb.Endpoint,
                 {LiveReloadSocket, :websocket}
               ),
               websocket_handler(
                 "/service_provider/live/websocket",
                 ServiceProvider.Endpoint,
                 {Phoenix.LiveView.Socket, :websocket}
               ),
               websocket_handler(
                 "/service_provider/phoenix/live_reload/socket/websocket",
                 ServiceProvider.Endpoint,
                 {LiveReloadSocket, :websocket}
               ),
               {:_, Cowboy.Handler, {Proxy.Plug, []}}
             ]}
          ]
        ]
      )
    ]
  end

  defp websocket_handler(path, endpoint, options) do
    {path, Phoenix.Endpoint.Cowboy2Handler, {endpoint, options}}
  end

  # we only want the proxy to start when phoenix is started as well
  # (not in iex or tests)
  defp in_phoenix? do
    Application.get_env(:phoenix, :serve_endpoints)
  end

  # defp to_port(nil) do
  # Logger.error(
  #  "Server can't start because :port in config is nil, please use a valid port number"
  # )

  # exit(:shutdown)
  # end

  # defp to_port(binary) when is_binary(binary), do: String.to_integer(binary)
  defp to_port(integer) when is_integer(integer), do: integer
  # defp to_port({:system, env_var}), do: to_port(System.get_env(env_var))
end

Receiving this error after upgrading deps, I have followed the upgrade guide from Chris.

https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html

  • handler is a module which implements the :cowboy_websocket behaviour. Note that this module will NOT have its c:cowboy_websocket.init/2 callback called; only the ‘later’ parts of the :cowboy_websocket lifecycle are supported

Phoenix dropped direct support for Cowboy’s websocket_handler behaviour when we shipped WebsockAdapter as part of Phoenix 1.7. WebSocket support within Phoenix is now mediated entirely via WebsockAdapter; Phoenix.Endpoint.Cowboy2Handler was removed entirely here (that module was only ever around because of the need for WebSocket support; HTTP connections have always been surfaced into Phoenix directly via Plug).

You shouldn’t actually need any of this any longer; WebSocket upgrades are now signalled entirely via Plug (including within Phoenix) and should be transparent to you.

3 Likes

The discussion on this thread may be relevant to your interests.

so PLug.Cowboy.Handler will Do?

It’s even simpler than that - you should be able to just pass Proxy.Plug as the (currently nil) value for plug in your Cowboy.child_spec call.

Note that you’ll need to define socket handlers in your Phoenix endpoint for each of the four WebSocket endpoints you have listed, but that’s all done within Phoenix itself (and you may have those already)