malli 2026-02-16

I am having some problems with multi schema and json-transform

(m/decode
   [:multi {:dispatch :type}
    [:kikka [:map
             [:type [:and [:= :kikka] :keyword]]
             [:kikka :int]]]]
   {:type "kikka" :kikka 1}
   (mt/json-transformer))
=> {:type "kikka", :kikka 1}
I'd have expected it to transform "kikka" to :kikka

If you check validate, it should say it is invalid

There should be explanation somewhere re multi dispatch and decoding

Here the dispatch doesn't match any branch because the value isn't same type as dispatch values. And the information about the wanted type is only inside the dispatch branch.

You need to decode the value at the multi schema level

https://github.com/metosin/malli/?tab=readme-ov-file#multi-schemas ":dispatch values should be decoded before actual values:"

(that sentence does sound a bit strange)

":dispatch values should be decoded before using as dispatch value"

(m/encode [:multi {:dispatch :type}
             [:kikka [:map
                      [:type [:= :kikka]]
                      [:kikka :int]]]] {:type :kikka :kikka 1}
            (mt/json-transformer))
=> {:type "kikka", :kikka 1}
Ok so before taking that to a roundtrip I should handle those dispatch values separately

just add the decode/string to :multi

or I guess you could write :dispatch fn to coerce to correct type

(m/decode
   [:multi {:decode/string keyword :dispatch :type}
    [:kikka [:map
             [:type 
              [:and [:= :kikka] :keyword]]
             [:kikka :int]]]]
   {:type "kikka" :kikka 1}
   (mt/json-transformer))
this is not it, seems like

decode/string at that level applies to the whole map

check the readme example

Not this either.

(m/decode
   [:multi {:dispatch :type}
    [:kikka [:map
             [:type {:decode/string keyword}
              [:and [:= :kikka] :keyword]]
             [:kikka :int]]]]
   {:type "kikka" :kikka 1}
   (mt/json-transformer))
Thanks Juho, I think I need to look into this a little more, I'm probably just being dumb here

ah, its probably at the lower level still

(m/decode [:multi {:dispatch :type :decode/string #(update % :type keyword)} .... )

I couldn't get that working but I resorted to adding a custom transformer that does it

Thanks for your help!