No function clause matching in Ecto.Changeset.add_constraint/6

I have added a unique constraint with the migration below

def up do
    create(unique_index(:tbl_wa_acc_details, [:passport_no, :acc_type_id], name: :unique_acc_with_passport)
  end

  def down do
    drop(index(:tbl_wa_acc_details, [:passport_no, :acc_type_id], name: :unique_acc_with_passport))
  end

and below is part of the schema

 |> multi_validate_format([:mobile, :country_code, :brn_code])
 |> unique_constraint([:passport_no, :acc_type_id], name: :unique_acc_with_passport, message: "already exists")

on insert am getting the error

no function clause matching in Ecto.Changeset.add_constraint/6

what Am I doing wrong??

What is multi_validate_format returning exactly?

def multi_validate_format(changeset, keys) do

    Enum.reduce(keys, changeset, fn field, changeset ->

      validate_format(changeset, field, @number_regex, message: " can't be alphanumeric")

    end)

  end

So, can you put an IO.inspect() between these two and paste the output?

   ** (FunctionClauseError) no function clause matching in Ecto.Changeset.add_constraint/6
        (ecto 2.2.12) lib/ecto/changeset.ex:2272: Ecto.Changeset.add_constraint(#Ecto.Changeset<action: nil, changes: %{place_of_birth: "Lusaka", sex: "M", title: "MR", user_id: 1, cust: "INDIV_MI", date_of_birth: "1998-23-04", relation_manager: "JEFF", passport_is_dt: "2002-20-01", last_name: "Tembo", image_id: "202021121", location: "ZM", country_of_birth: "ZM", marital_status: "M", middle_name: "S", nationality: "ZM", tax_id: "44444555555", city: "lusaka province", cust_category: "INDIVIDUAL NONE RESIDENT", uuid: "57b2fab3-088a-4d16-9ad8-b91dd4f2a3e9", region: "LUSAK_PRV", age_range: "30_AND_40", mobile: "964352098", physical_add: "C/O PROBASE", id_type: "NRC", first_name: "Chanda", passport_no: "202021121", emp_status: "P", brn_code: "002", occupation: "ENGINEER", acc_type_id: 1, postal_add: "P.O. Box NM42, Stand 16806", institution: "ENERGY_SE", email: "coilardium@gmail.com"}, errors: [], data: #BulkAccountOpening.BankAccounts.WaAccount<>, valid?: true>, :unique, "unique_acc_with_nrc", :exact, [:id_no, :acc_type_id], {"already exists", []})
`

we need to see what gets passed into add_constraint().

like so:

iex(1)> 1 |> IO.inspect(label: "this will go into div()") |> div(0)
this will go into div(): 1
** (ArithmeticError) bad argument in arithmetic expression: div(1, 0)
    :erlang.div(1, 0)

Passing a list of fields to unique_constraint was added in Ecto 3.4.2 (#3276), your most recent error message says ecto 2.2.12. For that version, unique_constraint takes the name of the field (passport_no, likely in your case) that should get the changeset error when the constraint is violated.

1 Like

I said between those two lines though. So the final code should be:

|> multi_validate_format([:mobile, :country_code, :brn_code])
|> IO.inspect(label: "after multi_validate_format")
|> unique_constraint([:passport_no, :acc_type_id], name: :unique_acc_with_passport, message: "already exists")

And then tell us what do you see on the console.

If you allow me one small piece of advice, being as brief (almost silent) as you are will not help you get answers on forums. People are more willing to help when you describe a problem in more details and with context (like library versions) and work with them when they are trying to help.

Thanks it was actually the version of ecto… Thanks for the help