larksuite/cli · error

%s field %s must declare json tag

Error message

%s field %s must declare json tag

What it means

This error comes from the typed shortcut data compiler when building an object shape from a struct. Every exported struct field must carry an explicit `json` tag so the compiler knows the wire name; a field without one makes the compiled schema ambiguous. The compiler refuses to guess a field name, so it fails at compile time of the type registration.

Source

Thrown at shortcuts/common/typed_compile_data.go:203

// 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) {
	if _, cyclic := active[t]; cyclic {
		return typedObjectShape{}, fmt.Errorf("recursive type %s requires an explicit Shape", t)
	}
	active[t] = struct{}{}
	defer delete(active, t)

	shape := typedObjectShape{}
	seen := make(map[string]string)
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		if !field.IsExported() {
			continue
		}
		rawJSON, ok := field.Tag.Lookup("json")
		if !ok {
			return typedObjectShape{}, fmt.Errorf("%s field %s must declare json tag", path, field.Name)
		}
		parts := strings.Split(rawJSON, ",")
		name := parts[0]
		if name == "-" {
			continue
		}
		if name == "" {
			return typedObjectShape{}, fmt.Errorf("%s field %s json tag must explicitly name the field", path, field.Name)
		}
		omitempty := false
		for _, option := range parts[1:] {
			switch option {
			case "omitempty":
				omitempty = true
			case "":
			default:
				return typedObjectShape{}, fmt.Errorf("%s field %s has unsupported json option %q", path, field.Name, option)
			}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Add an explicit `json` tag to the named field, e.g. `json:"fieldName"`
  2. Use `json:"-"` if the field is internal and should be excluded from the shape (it is then skipped)
  3. If the field should not be part of the schema at all, make it unexported

Example fix

// before
type Input struct {
    Name string
}
// after
type Input struct {
    Name string `json:"name" schema:"required" doc:"Display name"`
}
Defensive patterns

Strategy: validation

Validate before calling

for i := 0; i < t.NumField(); i++ {
    f := t.Field(i)
    if f.IsExported() {
        if _, ok := f.Tag.Lookup("json"); !ok {
            return fmt.Errorf("field %s needs a json tag", f.Name)
        }
    }
}

Prevention

When it happens

Trigger: Registering a struct with compileData/shapeForType where an exported field has no `json` tag at all, e.g. `Name string` without `json:"name"`.

Common situations: Adding a new field to an existing typed Data/Input struct and forgetting the tag; copying a struct from non-JSON code (internal models) into a typed shortcut definition; embedding types whose fields were previously serialized by other means.

Related errors


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