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

  1. Remove the field from Data or move it behind `json:"-"` if it is not part of the wire payload.
  2. Replace it with the JSON-representable form (e.g. store an opaque handle as string).
  3. Restructure so only plain JSON-mappable types (string/bool/int/float/slice/struct) appear in Data.
  4. 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

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


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/26743e060b82543d. Report an issue: GitHub.