Repository navigation
Description
What is the issue?
On a collection keyed by an enum, get(key:) and subset(keys:) accept any enum name, whether or not it is a member. A name that isn't a member reaches the key lookup, and the collection reports that it doesn't contain the key:
collection "Test" does not contain key "Red" in the current subset
Passed to an ordinary argument of the same enum, the same name is refused as invalid:
convert arg "color": invalid enum member "Red" for TestColor
I expected get and subset to refuse Red as an invalid member, as the ordinary argument does. Instead the error points at the collection's keys, not at the spelling. Red is an easy mistake to make: the member is ColorRed in the module's source and is registered as Red, and only callers see it as RED.
The key arguments take their type from TypeDef.ToInput() (get.Spec.Args and the subset field in core/collection_object.go). For an enum, that's a bare dagql.EnumValueName (core/typedef.go), which decodes any name without checking the members. collectionKeyFromInput then keeps the caller's text, and get and subset compare it with the keys' text. Ordinary function arguments are converted through the enum's own type (core/modfunc.go), which looks the name up among the members. collectionKeys already converts the stored keys through the enum type, so converting the requested keys the same way would refuse non-members with the usual error. main (af67915) has the same code.
I found this while porting the collection tests to a Rust SDK module, whose first query spelled a key the way the Rust source names the variant.
Dagger version
Version: v1.0.0-beta.25
commit: a45241b2
dirty: no
platform: darwin/arm64/v8
runner-host: image://registry.dagger.io/engine:v1.0.0-beta.25
Steps to reproduce
This is the module from TestEnumKeys in core/integration/collections_test.go, with engineVersion set to beta.25 and an ordinary enum argument, paint, added for comparison. Put these two files in a new Git repository.
dagger.json:
{"name":"test","engineVersion":"v1.0.0-beta.25","sdk":{"source":"go"},"source":"."}main.go:
package main
import (
"context"
"dagger/test/internal/dagger"
)
type Color string
const (
ColorRed Color = "red"
ColorBlue Color = "blue"
)
// +collection
type Test struct {
Keys []Color
Delta *dagger.CollectionDelta
}
func New() *Test { return &Test{Keys: []Color{ColorRed, ColorBlue}} }
func (*Test) Get(color Color) *Item { return &Item{Name: string(color)} }
func (colors *Test) Removed(ctx context.Context) ([]string, error) {
return colors.Delta.RemovedKeys(ctx)
}
// Paint takes the same enum as an ordinary argument.
func (*Test) Paint(color Color) string { return string(color) }
type Item struct{ Name string }In the module's directory, run these queries:
-
This query uses the members' names and works:
$ dagger query <<< '{ keys get(key: RED) { name } subset(keys: [BLUE]) { keys } }' { "get": { "name": "red" }, "keys": [ "RED", "BLUE" ], "subset": { "keys": [ "BLUE" ] } }
-
getreports the misspelt key as missing:$ dagger query <<< '{ get(key: Red) { name } }' -
subsetdoes the same:$ dagger query <<< '{ subset(keys: [Blue]) { keys } }' -
The ordinary argument refuses the name as invalid:
$ dagger query <<< '{ paint(color: Red) }'
The log output below shows the errors from queries 2–4, in order.
dagger call get --key=Red name prints red, because the CLI maps Red to RED before it calls the function. A self-call through the module's generated client works too, because the generated constant is RED. With engineVersion set to v1.0.0-beta.20, as in TestEnumKeys, get and subset behave the same way.
Log output
Error: make request: input: get collection "Test" does not contain key "Red" in the current subset
Error: make request: input: subset collection "Test" does not contain keys ["Blue"] in the current subset
Error: make request: input: paint set call inputs: convert arg "color": invalid enum member "Red" for TestColor
Activity
santhiprakash commentedon Nov 7, 2026
Nice catch — I'll put up a fix for this. The plan is to validate the requested keys against the enum's members in
getandsubset, so a name that isn't a member is refused with the usualinvalid enum membererror instead of being reported as a key the collection doesn't contain.