Migrate non optional field with Serde

I try to migrate a new non optional field in my heap memory using Serde but, I get following error:

  Request ID: 2e0dc0659e5c1c445882d82deadd0df89c18a0f074b24b5b5d533852aa011fea
  Reject code: 5
  Reject text: Canister xo2hm-lqaaa-aaaal-ab3oa-cai trapped explicitly: Panicked at 'called `Result::unwrap()` on an `Err` value: "Custom(Fail to decode argument 0\n\nCaused by:\n    Subtyping error: field memory is not optional field)"', src/satellite/src/lib.rs:104:50

    at m_ (file:///opt/homebrew/lib/node_modules/@junobuild/cli/dist/index.js:42:2120)

i.e. field memory is not optional field

My struct look like:

#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
    pub struct Rule {
        #[serde(default)]
        pub memory: Memory,
    }

#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
    pub enum Memory {
        Heap,
        Stable,
    }

And I got an implementation

impl Default for Memory {
    fn default() -> Self { Memory::Heap }
}

What am I missing?

You need serde(default) for Memory too I believe.

Try this :

#[derive(CandidType, Serialize, Deserialize, Default, Clone, Debug)]
    pub enum Memory {
        #[default]
        Heap,
        Stable,
    }

also try deriving Default for Rule.

#[derive(CandidType, Serialize, Deserialize, Default, Clone, Debug)]
    pub struct Rule {
        #[serde(default)]
        pub memory: Memory,
    }

1 Like

Thanks, did not thought about it. Unfortunately though, same same.

#[derive(CandidType, Serialize, Deserialize, Default, Clone, Debug)]
    pub struct Rule {
        #[serde(default)]
        pub memory: Memory,
    }

// Deleted my implementation

#[derive(CandidType, Serialize, Deserialize, Default, Clone, Debug)]
    pub enum Memory {
        #[default]
        Heap,
        Stable,
    }

Also tried to bump last version of Serde, just in case.

Is this a backward compatibility issue? Have you tried reinstalling the canister?

Otherwise you can do Option<Memory> as a measure to allow backward compatibility but it’s probably not needed this early on.

I try to upgrade existing canister without reinstalling those - preserving the state.

I can set the memory as Option<Memory> but, because it’s a really important information, I was hoping to be able to introduce it as a non optional value. Just feel wrong to have it optional but, indeed if no other option, I ultimately have to, agree with you.

If you want to preserve the state then yeah you’d have to introduce optional types.

Or what we’re doing is ensuring that every single type has a valid default (even if it’s something like Unspecified which won’t pass a validation check.)

That way you can change the schema, and when you deserialize into the type it

a) skips values that exist in the serialized data that don’t exist in the new type
b) sets a default for values that don’t exist in the data but are new to the type.

As long as your types have Serialize/Deserialize and Default this should work. We haven’t really tested it a lot though.

1 Like

I had to fix some stuffs in a FE project so, when I finally went back to mine I decided to accept my fate and set those new variable as Option<Memory>.

Upgrade worked like a charm and now there is the first Juno’s smart contract on mainnet that supports stable memory.

Thanks a lot for the help!

2 Likes

No problems. When we’ve done more testing on our ORM I’ll be happy to share it to see if it helps.

2 Likes