You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Elixir Phoenix中nil.email/0未定义或私有错误排查与修复咨询

Fixing "function nil.email/0 is undefined or private" in Elixir Phoenix

Hey there! Let's break down this error, address your questions, and get your code back on track.

What's causing this error?

This error is straightforward: you're trying to call email() on a nil value. In Elixir, when you have a variable that's nil (meaning it has no valid value assigned) and you try to access a field like user.email, Elixir throws this error because nil doesn't have an email/0 function or property.

Is this caused by database user ID conflicts?

Nope! Database ID conflicts would trigger database-level errors (like a unique constraint violation when inserting a duplicate ID), which are completely separate from this issue. This error has nothing to do with ID conflicts.

Why might the error source not be the current file?

Your UserView code is where the error is being raised, but the root cause lives upstream. The user variable being passed into user_json(user) is nil because wherever this view is being called from (usually a controller action like UserController.show) is sending a nil instead of a valid User struct.

For example, if your controller uses Repo.get(User, id) to fetch a user, and the ID doesn't exist in the database, Repo.get returns nil. If you pass that nil directly to render("show.json", %{user: user}), the view will try to call nil.email and crash immediately.

How to fix it

Here are a few solid approaches to resolve this:

Catch the nil case early in your controller before passing data to the view. This lets you return a proper 404 response when the user doesn't exist:

defmodule MessengyrWeb.UserController do
  use MessengyrWeb, :controller
  alias Messengyr.Accounts.User
  alias Messengyr.Repo

  def show(conn, %{"id" => id}) do
    case Repo.get(User, id) do
      nil ->
        conn
        |> put_status(:not_found)
        |> json(%{error: "User not found"})

      user ->
        render(conn, "show.json", user: user)
    end
  end
end

2. Add a nil clause in your view's user_json function

If you want to prevent the view from crashing even if a nil is passed, add a clause that handles nil explicitly:

defmodule MessengyrWeb.UserView do
  use MessengyrWeb, :view

  def render("show.json", %{user: user}) do
    %{user: user_json(user)}
  end

  # Handle nil users first
  def user_json(nil), do: %{error: "User not available"}

  def user_json(user) do
    hash_email = :crypto.hash(:md5, user.email) |> Base.encode16() |> String.downcase()
    avatar_url = "http://www.gravatar.com/avatar/#{hash_email}"

    %{
      id: user.id,
      email: user.email,
      avatar_url: avatar_url
      # Add other user fields here
    }
  end
end

3. Use bang functions for stricter fetching

Phoenix/Ecto provides "bang" versions of query functions (like Repo.get!) that raise an Ecto.NoResultsError if no record is found. You can then handle this error globally in your ErrorView to return a 404:

In your controller:

def show(conn, %{"id" => id}) do
  user = Repo.get!(User, id)
  render(conn, "show.json", user: user)
end

In your ErrorView:

defmodule MessengyrWeb.ErrorView do
  use MessengyrWeb, :view

  def render("404.json", _assigns) do
    %{error: "Resource not found"}
  end

  def template_not_found(template, _assigns) do
    status = Phoenix.Controller.status_message_from_template(template)
    %{error: status}
  end
end

内容的提问来源于stack exchange,提问作者s15o

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:05:00