Mix test - Postgrex.Error ERROR 42703 (undefined_column) column when running "player_tag" of relation "heroes" does not exist

Hello!

I have a Player schema and each player can have multiple heroes (one-to-many) when trying to insert a Player with associated Heroes in my tests, they fail. The weird thing is that when I run my app iex -S mix and try to insert a Player with Heroes it works! But not in the tests :massage_man:t2:

1) This is my Heroe schema:

defmodule Iclash.Repo.Schemas.Heroe do
  use Ecto.Schema
  import Ecto.Changeset

  @optional_fields [:player_tag, :inserted_at, :updated_at]
  @required_fields [:name, :level, :max_level, :village]

  @primary_key false
  schema "heroes" do
    field :name, :string, primary_key: true
    field :level, :integer, primary_key: true
    field :max_level, :integer
    field :village, Village

    belongs_to :player, Player,
      foreign_key: :player_tag,
      primary_key: true,
      type: :string,
      references: :tag,
      on_replace: :update

    timestamps(type: :utc_datetime_usec)
  end

  def changeset(%__MODULE__{} = heroe, attrs \\ %{}) do
    heroe
    |> cast(attrs, @required_fields ++ @optional_fields)
    |> validate_required(@required_fields)
  end
end

2) This is my Heroe migration:

defmodule Iclash.Repo.Migrations.AddHeroesTable do
  use Ecto.Migration

  def change do
    create table(:heroes, primary_key: false) do
      add :player_tag,
          references(:players,
            column: :tag,
            type: :string,
            on_delete: :delete_all,
            on_update: :update_all
          ),
          primary_key: true

      add :name, :string, primary_key: true
      add :level, :integer, primary_key: true
      add :max_level, :integer, null: false
      add :village, :string, null: false

      timestamps(type: :utc_datetime_usec)
    end
  end
end

3) This is the test I try to run:

  setup do
    now = ~U[2025-08-08 12:00:00.000000Z]
    five_minutes_later = DateTime.add(now, 5, :minute)

    heroes_map = [
      %{
        player_tag: "#P1",
        name: "HERO 1",
        level: 100,
        max_level: 100,
        village: "home",
        inserted_at: now,
        updated_at: now
      },
      %{
        player_tag: "#P1",
        name: "HERO 2",
        level: 100,
        max_level: 100,
        village: "home",
        inserted_at: five_minutes_later,
        updated_at: five_minutes_later
      }
    ]

    {:ok, player} =
      %{
        tag: "#P1",
        name: "PLAYER 1",
        trophies: 100,
        town_hall_level: 17,
        best_trophies: 100,
        attack_wins: 10,
        defense_wins: 10,
        role: "admin",
        war_preference: "in",
        heroes: heroes_map,
        inserted_at: now,
        updated_at: now
      }
      |> PlayerSchema.to_struct()

    %{now: now, player: player}
  end

  describe "get_player/1" do
    test "Gets a player and return player struct", %{player: player} do
      {:ok, inserted_player} = Repo.insert(player) # <--- This is the line of the error.
      ...
    end
  end
end

4) This is the error im getting:

  1) test get_player/1 Gets a player and return player struct (Iclash.DomainTypes.PlayerTest)
     test/iclash/domain_types/player_test.exs:53
     ** (Postgrex.Error) ERROR 42703 (undefined_column) column "player_tag" of relation "heroes" does not exist

         query: INSERT INTO "heroes" ("name","level","player_tag","inserted_at","updated_at","max_level","village") VALUES ($1,$2,$3,$4,$5,$6,$7)
     code: {:ok, inserted_player} = Repo.insert(player)
     stacktrace:
       (ecto_sql 3.12.1) lib/ecto/adapters/sql.ex:1096: Ecto.Adapters.SQL.raise_sql_call_error/1
       (ecto 3.12.5) lib/ecto/repo/schema.ex:837: Ecto.Repo.Schema.apply/4
       (ecto 3.12.5) lib/ecto/repo/schema.ex:416: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
       (ecto 3.12.5) lib/ecto/association.ex:948: Ecto.Association.Has.on_repo_change/5
       (ecto 3.12.5) lib/ecto/association.ex:648: anonymous fn/8 in Ecto.Association.on_repo_change/7
       (elixir 1.17.0) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
       (ecto 3.12.5) lib/ecto/association.ex:644: Ecto.Association.on_repo_change/7
       (elixir 1.17.0) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
       (ecto 3.12.5) lib/ecto/association.ex:589: Ecto.Association.on_repo_change/4
       (ecto 3.12.5) lib/ecto/repo/schema.ex:1021: Ecto.Repo.Schema.process_children/5
       (ecto 3.12.5) lib/ecto/repo/schema.ex:1099: anonymous fn/3 in Ecto.Repo.Schema.wrap_in_transaction/6
       (ecto_sql 3.12.1) lib/ecto/adapters/sql.ex:1400: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
       (db_connection 2.7.0) lib/db_connection.ex:1756: DBConnection.run_transaction/4
       test/iclash/domain_types/player_test.exs:54: (test)

This indicates that there’s a missing column in your table. Did you add new migration file, did you change existing migrations file - but didn’t run migrations in test?

Try running: MIX_ENV=test mix ecto.migrate

If it doesn’t help, try removing test database and running migrations from scratch:

MIX_ENV=test mix ecto.drop
MIX_ENV=test mix setup

NOTE: The first command will delete all your tables!

2 Likes

Hey! Thanks so much! It’s working, completely forgot to migrate my test env :flushed:.