Persistent "Stable interface compatibility check failed" error

If I have a canister that contains a stable Trie, I get the following message every time I try to deploy, even if I’ve made no changes since the last time I deployed:

WARNING!
Stable interface compatibility check failed for canister 'stability'.
Upgrade will either FAIL or LOSE some stable variable data.

.../ic-projects/stability/.dfx/local/canisters/stability/stability.old.most:2.39-2.40: syntax error [M0001], unexpected token '/', expected one of token or <phrase> sequence:
  }
  <typ_args>?
  ; seplist(<typ_field>,<semicolon>)
  or <typ>
  . <id>
  -> <typ_nobin>
  and <typ>

Do you want to proceed? yes/No

I have to answer “yes” every time I want to deploy, even if no stability-disrupting changes have been made. The only way I can get dfx to not ask me is to delete the .dfx folder or restart dfx with --clean specified, but then of course I run into the same issue the next time I try to deploy. Possibly the error in the .old.most file mentioned in the warning is causing the comparison to consider any changes as stability-breaking.

Here are the contents of stability.old.most:

type Branch<K, V> = {left : Trie<K, V>; right : Trie<K, V>; size : Nat};
type Leaf<K, V> = {keyvals : AssocList/1<Key<K>, V>; size : Nat};
actor {
  stable var test :
    {#branch : Branch<Nat, Nat>; #empty; #leaf : Leaf<Nat, Nat>}
};

This happens with the default project created with “dfx new” under dfx 0.9.2 if a stable variable like the following is in the actor, even if it’s not new or changed between deploys:

stable var test : Trie.Trie<Nat, Nat> = Trie.empty();

But not when the stable variable is a Nat, for example:

stable var test : Nat = 1;

3 Likes

Yes I’m getting the same error… No changes to any of my files (git status returns nothing)… but when I run dfx deploy I get this error (which I can override by typing in Yes but still…):

Installing canisters...
WARNING!
Stable interface compatibility check failed for canister 'service'.
Upgrade will either FAIL or LOSE some stable variable data.

/Users/justinchiang/project/.dfx/local/canisters/service/service.old.most:19.10-19.11: syntax error [M0001], unexpected token '/', expected one of token or <phrase> sequence:
  = <typ>
  < seplist(<typ_bind>,,) > = <typ>

Do you want to proceed? yes/No
No
Error: Refusing to install canister without approval

Line 19 of that file is this:

type Char/2 = Char/1;

@chenyan have you happened to have seen this before? Thanks.

2 Likes

This will be fixed in the next moc release. You can also patch this PR (bugfix: fix pretty printing of types and #3128 by crusso · Pull Request #3130 · dfinity/motoko · GitHub) if you want to build it yourself.

1 Like

Yeah, sorry folks, that’s my bad.

I could put out another release of moc tomorrow, if you know how to patch your dfx to use it. Environment variable DFX_MOC_PATH apparently let’s you repoint dfx to another moc, though I’ve never tried it.

2 Likes

There’s a new release of moc you can try here:

If you manage to try it, please let me know if it works for you.

I just tried it, but unfortunately it throws a new error when running dfx build (so even before the canister installation step):

stable-types:6.6-6.15: type error [M0051], duplicate definition for type AssocList in block

I confirmed this issue does not exist in 0.6.21.

OK, that’s not good. Thanks for trying!

You might want to stick with 0.6.21(or 0
6.22) for now since you can at least ignore the dfx warning.

0.6.23 should actually fail to produce a binary if there is something wrong with the ‘.most’ file or custom section (it does an extra sanity check).

I think I’ve found and fixed the bug in 0.6.23.

If you get a chance, please try the newest release, moc 0.6.24, and let me know how that works for you.

1 Like

Hmm, I ran it again on 0.6.24, and that error went away but now I have a different error:

stable-types:33.16-33.23: type error [M0029], unbound type Char__1

Same as before—exit code is 255.

OK, thanks for checking. Guess I’ll be working on that today ;->

2 Likes

I’m a little embarrassed to ask, but could you try:

and see if it fixes this issue?

I’d be happy to try, but I’m not sure how. Can you point to some resources explaining how to use a custom moc?

I’m just guessing, but I think you download the new moc binaries and then try

export DFX_MOC_PATH=<path to new moc>

and then use dfx as before.

Update:

I just tried (in a new dfx project)

export DFX_MOC_PATH=/home/crusso/motoko/bin/moc
dfx deploy 

‘/home/crusso/motoko/bin/moc’ is where my locally built moc lives and it worked fine.
You might have to make the moc you download executable first.

(Related post: DFX deploy with custom Motoko version)

1 Like

AFK right now, but I’ll try again with 0.6.25 tonight!

1 Like

So the good news is that dfx build now succeeds without error.

But dfx deploy still shows the original error even when I make no changes to my stable variable interface:

Installing canisters...
WARNING!
Stable interface compatibility check failed for canister 'service'.
Upgrade will either FAIL or LOSE some stable variable data.

/Users/justinchiang/yelp2/.dfx/local/canisters/service/service.old.most:19.10-19.11: syntax error [M0001], unexpected token '/', expected one of token or <phrase> sequence:
  = <typ>
  < seplist(<typ_bind>,,) > = <typ>

Do you want to proceed? yes/No
No
Error: Refusing to install canister without approval

And line 19 of service.old.most is still the same line:

type Char/2 = Char/1;
3 Likes

Great, thanks for helping out!

Right, but I think that makes sense if the deployed version was built with the buggy compiler and contains an ill-formed stable-types section. The dfx deploy will try to parse the old.most as well as the new.most, but old.most is still broken.

I expect that if you click through and do the upgrade, the next upgrade, with both old and new code built by non-buggy compiler, should work without error or click thru warning.

1 Like

I expect that if you click through and do the upgrade, the next upgrade, with both old and new code built by non-buggy compiler, should work without error or click thru warning.

Let me know if that resolves the error. If so, I think we are good to go with this version of moc.

Ah gotcha, so the old.most file is generated after I click “yes” and not before…

Yep, the error goes away now when I run dfx deploy with 0.6.25. But when I run dfx deploy with the currently released version of moc, the error returns (as expected).

Just to confirm, I made a small stable-incompatible change to one of my types (i.e. made an immutable field mutable), and when I ran it with 0.6.25 I get this error:

(unknown location): Compatibility error [M0170], stable variable shops of previous type
  var
   {
     #branch : Branch<ShopId, ShopInfo>;
     #empty;
     #leaf : Leaf<ShopId, ShopInfo>
   }
cannot be consumed at new type
  var
   {
     #branch : Branch__1<ShopId__1, ShopInfo__1>;
     #empty;
     #leaf : Leaf__1<ShopId__1, ShopInfo__1>
   }

It makes sense that I get this error, but how do I actually debug what ShopId__1 and ShopInfo__1 are? If the old.most file hasn’t been generated yet, does that mean there’s no way for me to dig deeper into the type error?

1 Like

Thanks again!

The stable-types custom section/’.most’ file is stored in the canisters wasm and generated by the compiler that produced the wasm.

Dfx deploy merely reads the sections from the new and old canisters and calls ‘moc - -stable-compatible’ to compare them. After a compiler upgrade, this means you might be checking compatibility between stable types signature produced by different compiler versions. In this case, one that produced ill-formed signatures ( and one that (hopefully) now does not.

Good point about debugging. Hopefully dfx leaves the files on the filesystem somewhere otherwise the user will need to recreate them by querying the IC, examining the wasm or running ‘moc - - stable-types’ …

3 Likes

can those flags be documented please?