larksuite/cli · error
Go type %s cannot be mapped to a ValueShape
Error message
Go type %s cannot be mapped to a ValueShape
What it means
The compiler's reflect-based switch ran out of kinds: the field's Go type is something (after pointer unwrapping) that has no JSON mapping in the shape system — e.g. func, chan, complex numbers, or unsafe pointers. It cannot be mapped to a ValueShape, so registration fails with the concrete type named.
Source
Thrown at shortcuts/common/typed_compile_data.go:169
shape = typedArrayShape{Items: elementShape, MinItems: schema.minItems, MaxItems: schema.maxItems}
case reflect.Struct:
if implementsCustomEncoding(baseType) {
return nil, fmt.Errorf("custom JSON type %s requires an explicit Shape", baseType)
}
if len(schema.enum) > 0 || hasStringConstraints(schema) || hasNumberConstraints(schema) || hasItemConstraints(schema) || schema.format != "" {
return nil, fmt.Errorf("object field has incompatible schema constraint")
}
object, err := compileStructShape(baseType, input, baseType.String(), active)
if err != nil {
return nil, err
}
shape = object
case reflect.Map:
return nil, fmt.Errorf("map type %s requires an explicit Shape", baseType)
case reflect.Interface:
return nil, fmt.Errorf("interface type %s requires an explicit Shape", baseType)
default:
return nil, fmt.Errorf("Go type %s cannot be mapped to a ValueShape", t)
}
if schema.nullable != nil && *schema.nullable {
shape = typedOneOfShape{Variants: []typedValueShape{shape, typedNullShape{}}}
}
return shape, nil
}
// compileStructShape walks one struct into an ObjectShape. active holds the
// struct types already open on the current recursion path, so a type that
// refers back to itself is reported as a compile error. Without the guard the
// walk never terminates and the goroutine stack is exhausted -- that is a
// fatal runtime error, not a panic, so no recover boundary can contain it and
// the whole CLI dies during command registration.
//
// Membership is scoped to the path rather than the whole walk: a type is
// removed once its fields are compiled, so the same type appearing twice as a
// sibling stays legal.
func compileStructShape(t reflect.Type, input bool, path string, active map[reflect.Type]struct{}) (typedObjectShape, error) {View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Remove the field from Data or move it behind `json:"-"` if it is not part of the wire payload.
- Replace it with the JSON-representable form (e.g. store an opaque handle as string).
- Restructure so only plain JSON-mappable types (string/bool/int/float/slice/struct) appear in Data.
- For pointer-typed fields remember pointers are unwrapped; the error names the base type — fix the base kind.
Example fix
// before
type Data struct {
Hook func() `json:"hook"` // unmappable
}
// after
type Data struct {
Hook string `json:"hook"` // opaque handle/id
} Defensive patterns
Strategy: validation
Validate before calling
func mappable(t reflect.Type) bool {
for t.Kind() == reflect.Pointer { t = t.Elem() }
switch t.Kind() {
case reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16,
reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16,
reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64,
reflect.Slice, reflect.Array, reflect.Struct:
if t.Kind() == reflect.Struct {
for i := 0; i < t.NumField(); i++ {
if !mappable(t.Field(i).Type) { return false }
}
}
if t.Kind() == reflect.Slice || t.Kind() == reflect.Array {
return mappable(t.Elem())
}
return true
}
return false // func, chan, complex, etc.
} Type guard
func isMappableKind(k reflect.Kind) bool {
switch k {
case reflect.String, reflect.Bool, reflect.Int, reflect.Int64, reflect.Float64,
reflect.Slice, reflect.Struct:
return true
}
return false
} Prevention
- Exclude funcs, channels, and complex numbers from wire structs; use `json:"-"` if they must exist on the type.
- Keep runtime-only state in a separate struct from Data.
- Run a reflect-based mappability check in tests over every Data type.
When it happens
Trigger: A Data struct (or nested field reached via collectArgFields/shapeForType) declares a field of an unmappable kind such as func, chan, complex128, or uintptr.
Common situations: Callback/handle fields accidentally included in wire structs; complex numbers from math code; generated structs containing runtime-only members.
Related errors
- json.RawMessage requires an explicit Shape
- byte slice or array %s requires an explicit Shape
- custom JSON type %s requires an explicit Shape
- map type %s requires an explicit Shape
- interface type %s requires an explicit Shape
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/26743e060b82543d.
Report an issue: GitHub.