An s/keys
spec will silently do nothing if it is defined without any valid arg key ( :req
, :req-un
, :opt
, :opt-un
, :gen
).
Using req-un
instead of :req-un
(symbol instead of keyword, perhaps accidentally):
user> (s/def ::foo (s/or :string string? :number number?))
:user/foo
user> (s/def ::foo-map-broken (s/keys req-un [::foo]))
:user/foo-map-broken
user> (s/conform ::foo-map-broken {:foo []})
{:foo []}
;;arg key can be anything
user> (s/def ::foo-map-broken2 (s/keys 42 [::foo]))
:user/foo-map-broken2
user> (s/conform ::foo-map-broken2 {:foo []})
{:foo []}
My two cents: I tend to think calls to s/keys
should be validated more aggressively so this produces an error. The only argument I can think of in favor of the current behavior is that the args to s/keys
are effectively a map and maps are usually not treated as closed in Clojure. But 1> args that result in nothing happening still seem worth erroring on and 2> the user does not actually pass a map and may not realize that the implementation turns their arg keys and arg values into a map.
(I came across this behavior when clj-kondo flagged a spec of mine as incorrect and I noticed a typo just like above where I had req-un
instead of :req-un. I fixed :req-un to be a keyword and this uncovered bugs in the spec but it had been a few months since I touched the code so I wished I had discovered it sooner :--) )