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

Elixir Ecto报comparison with nil is forbidden错误排查

问题原因

报错触发的核心逻辑有两点:

  1. 新版本Ecto新增了强制校验:禁止在查询条件中用==和nil做比较,判断字段为nil必须用is_nil/1语法,否则直接抛出comparison with nil is forbidden的错误,之前部署能运行是因为旧版本Ecto没有加这个强制拦截。
  2. 你写的两个raw_id_by_name_tenant/2函数匹配逻辑有漏洞:Elixir函数匹配是从上到下按优先级匹配,你写的第一个函数头defp raw_id_by_name_tenant(name, tenant_id)没有加任何守卫限制,会匹配所有第二个参数的输入(包括nil),第二个写的兜底函数defp raw_id_by_name_tenant(name, _)永远不会被触发。当你在case分支里调用raw_id_by_name_tenant(@default_name, nil)时,实际命中的是第一个带租户过滤的函数,生成了l.tenant_id == nil的非法查询条件,直接触发报错。
修复方法

调整两个私有函数的匹配规则,明确区分tenant_id为nil和非nil的场景,从根源避免nil传入带租户过滤的查询:

def id_by_name_tenant(name, tenant_id) do
  id = raw_id_by_name_tenant(name, tenant_id)

  case id do
    nil -> raw_id_by_name_tenant(@default_name, nil)
    _ -> id
  end
end

# 第二个参数为nil时,走无租户ID过滤的查询
defp raw_id_by_name_tenant(name, nil) do
  from(
    l in MTModel.Location,
    where: l.name == ^name,
    limit: 1,
    select: l.id
  ) |> MTModel.Repo.one()
end

# 加非nil守卫,确保只有tenant_id合法时才走租户过滤逻辑
defp raw_id_by_name_tenant(name, tenant_id) when not is_nil(tenant_id) do
  from(
    l in MTModel.Location,
    where: l.name == ^name and l.tenant_id == ^tenant_id,
    limit: 1,
    select: l.id
  ) |> MTModel.Repo.one()
end

修复后逻辑:

  • 传入tenant_id为nil时,会精准匹配到无租户过滤的查询函数,不会生成非法的nil比较条件
  • 非nil的tenant_id才会进入带租户过滤的查询,完全符合最初的代码设计预期
  • 移除了原代码中Repo.one([])里多余的空列表参数,符合Ecto的常规调用写法

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 14:57:26