This is an unfortunate corner case. A list pattern is expected to have a literal keyword in position 1 or 2; the keyword is used in dispatching the emit-pattern-for-syntax multimethod. In your first case, you have literal keywords in both positions; if you look at the dispatch function for emit-pattern-for-syntax, you'll see that in this case, the first keyword wins. Since no pattern syntax is defined for :k1, you get the error. I believe quoting the :k1 literal ought to work in this case:
Fails:
(let [x [:k1 :k2 :k3]] (m/match [x] [(:k1 :<< first)] :first))
Invalid list syntax :<< in (:k1 :<< first). Valid syntax: [[:default :guard] [:or :default] [:default :only] [:default :seq] [:default :when] [:default :as] [:default :<<] [:default :clojure.core.match/vector]]
Work:
(let [k1 :k1 x [:k1 :k2 :k3]] (m/match [x] [(k1 :<< first)] :first))
Is it a bug or a feature?
How to match keywords correctly?