larksuite/cli · error
Args must be a non-pointer struct, got %s
Error message
Args must be a non-pointer struct, got %s
What it means
compileInput validates the Args struct type of a typed shortcut input definition via reflection. It throws this error when the reflected Args type's Kind() is not reflect.Struct — e.g. a pointer to struct (*MyArgs), a map, or a slice was passed. The typed-input machinery requires a concrete non-pointer struct so it can enumerate fields with tags.
Source
Thrown at shortcuts/common/typed_compile_args.go:26
"encoding/json"
"fmt"
"math"
"reflect"
"regexp"
"strconv"
"strings"
)
var (
flagNamePattern = regexp.MustCompile(`^[a-z0-9]+(?:-[a-z0-9]+)*$`)
aliasNamePattern = regexp.MustCompile(`^[a-z0-9][a-z0-9_-]*$`)
)
const extensionCommandPkgPath = "github.com/larksuite/cli/extension/command"
func compileInput(argsType reflect.Type, definition typedInputDefinition) ([]compiledInputField, map[string]int, error) {
if argsType.Kind() != reflect.Struct {
return nil, nil, fmt.Errorf("Args must be a non-pointer struct, got %s", argsType)
}
supplements := make(map[string]typedInputField, len(definition.Fields))
for i, supplement := range definition.Fields {
if !flagNamePattern.MatchString(supplement.Name) {
return nil, nil, fmt.Errorf("Input.Fields[%d].Name %q is not a canonical flag name", i, supplement.Name)
}
if _, exists := supplements[supplement.Name]; exists {
return nil, nil, fmt.Errorf("Input.Fields contains duplicate flag %q", supplement.Name)
}
supplements[supplement.Name] = supplement
}
var fields []compiledInputField
seenGo := make(map[string]struct{})
if err := collectArgFields(argsType, nil, false, &fields, seenGo, supplements); err != nil {
return nil, nil, err
}
fieldByName := make(map[string]int, len(fields))
allNames := make(map[string]string, len(fields))View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Change the Args type from a pointer (*T) to the plain struct value type T.
- If the args are dynamic, use the loose/untyped input path instead of the typed compile path.
- If Args is an alias to a non-struct type, define a real struct with flag/arg tags.
Example fix
// before
var def = typedInputDefinition{ Args: reflect.TypeOf(&CreateTaskArgs{}) }
// after
var def = typedInputDefinition{ Args: reflect.TypeOf(CreateTaskArgs{}) } Defensive patterns
Strategy: validation
Validate before calling
func validateArgsType(t reflect.Type) error {
if t == nil { return errors.New("Args type is nil") }
if t.Kind() == reflect.Pointer { t = t.Elem() }
if t.Kind() != reflect.Struct {
return fmt.Errorf("Args must be a non-pointer struct, got %s", t)
}
return nil
} Type guard
func isStructValue(v any) bool {
t := reflect.TypeOf(v)
return t != nil && t.Kind() == reflect.Struct
} Prevention
- Always declare Args as a plain struct value type, never *T.
- Add a unit test that compiles every shortcut definition at init or in CI.
- Never pass map/slice-based arg containers to the typed input path.
When it happens
Trigger: Passing *MyArgs (pointer-to-struct), a map, slice, or interface type as the Args value of a typedInputDefinition, or registering a shortcut whose args generic parameter resolves to a non-struct kind.
Common situations: Declaring shortcuts with a pointer receiver-style Args type like &Config{} by habit; copying a definition that used a map[string]any for loose input; refactoring that changed a struct parameter to a pointer for 'optional' semantics.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- field %q: %w
- %v overflows %s
- %T is not assignable to %s
- Args field %s flag --%s duplicates %s
- Input.Fields references unknown flag --%s
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/312999b62f5cf7f9.
Report an issue: GitHub.