Propagated fix from Elixir 1.12 branch to Elixir 1.7 and get `** (UndefinedFunctionError) function :rollback.errors/0 is undefined (module :rollback is not available)` when examining changeset errors

I made a change in our 1.12 branch (which works fine there) and we decided to cherry-pick it back to the 1.7 branch. When I run tests I get an error when trying to assert the content of changeset.errors that says:
** (UndefinedFunctionError) function :rollback.errors/0 is undefined (module :rollback is not available)
I get the same error just trying to inspect changeset.errors (or even Map.from_struct(changeset.errors)).

Is there perhaps a :rollback module embedded in 1.12 that has to be explicitly included in 1.7? (I tried adding :rollback as an extra app with no luck.) But if that’s the case why would I never have seen an error like this in any other tests that examine errors?
(Possible hint: the errors are actually from a field that is a has_one member of the current schema, and the error has been transferred from the associated schema to the virtual field on the parent schema.)

Test:

    test "error", %{channel: channel} do
      params = %{retention_policy_max_age: "0"}

      {:error, changeset} =
        channel
        |> Channel.preload_schema([:retention_policy])
        |> Channel.update(params)

      #IO.inspect(Map.from_struct(changeset.errors))
      assert changeset.errors == [
               retention_policy_max_age:
                 {"must be greater than %{number}",
                  [validation: :number, number: 0]}
      ]
    end

Error:

  1) test retention_policy error (MyApp.ChannelTest)
     myapp/models/channel_test.exs:769
     ** (UndefinedFunctionError) function :rollback.errors/0 is undefined (module :rollback is not available)
     code: assert changeset.errors == [
     stacktrace:
       :rollback.errors()
       myapp/models/channel_test.exs:778: (test)

I inspected the changeset error from the module for RetentionPolicy, before it was added to the virtual field in Channel:

17:00:36.442 [error]MyApp.Schema.Channel.handle_retention_params/2:220 #Ecto.Changeset<action: nil, changes: %{retention_policy_max_age: 0}, errors: [retention_policy_max_age: {"must be greater than %{number}", [validation: :number, number: 0]}], data: #MyApp.Settings.Schema.RetentionPolicy<>, valid?: false>

Any ideas what is going on? Using Ecto 2.1.6 on the 1.7 branch, versus 3.7.1 with 1.12.

1 Like

Basic sanity check: Did you rm -rf _build after switching to a different elixir version?

This sounds like a similar issue:

Folks in that issue are expecting {:error, changeset()} but get {:error, :rollback}.

The commit that Jose links at the end is only in 3.x

Tangentially, I would seriously reconsider trying to maintain an active 1.7 branch, it was released nearly 4 years ago.

2 Likes

I have two different machines, one running 1.7 the other 1.12. That’s because the base OS is also completely different, not because of the Elixir environment.

I’m far less worried about trying to maintain a project based on 1.7 than I am on the fact that the underlying OS of that version is Centos 6. :slight_smile: Which is why we are trying to finish a Linux 8 upgrade, which enabled the switch to Elixir 1.12/13. There’s a whole mess of upgrading approaching completion, but we need at least one more up-issue of the 1.7 based version.

For my next bit of fun I have about 17 Elixir packages spitting compile warnings, mostly for deprecated functions or constructs, or bad security or what have you. Need to research all of them to check out latest versions, etc. I had 18 but managed to trigger a package owner to merge a PR for the 1.9 changes.

I realized that I was always trying to do something with the second half of the return from update. The trick is that the whole return was just `{:error, :rollback}’. Since this is just a test for a backwards propagation I’ve just change the test to assert that the second element is :rollback and I’ll move on.

Thanks.