larksuite/cli · error

segment %q traverses non-object shape

Error message

segment %q traverses non-object shape

What it means

mutateObjectField walks a JSON-pointer path segment by segment to reach the field a DataField override targets. When an intermediate segment names a field whose shape is neither an object nor a oneOf-with-object-variants shape (e.g. a string, array, or scalar), traversal cannot continue and the compiler throws this error. It means the override path descends through a non-object field.

Source

Thrown at shortcuts/common/typed_compile_data.go:400

		if len(parts) == 1 {
			return mutate(field)
		}
		switch nested := field.Shape.(type) {
		case typedObjectShape:
			err := mutateObjectField(&nested, parts[1:], mutate)
			field.Shape = nested
			return err
		case typedOneOfShape:
			for variantIndex, variant := range nested.Variants {
				if nestedObject, ok := variant.(typedObjectShape); ok {
					err := mutateObjectField(&nestedObject, parts[1:], mutate)
					nested.Variants[variantIndex] = nestedObject
					field.Shape = nested
					return err
				}
			}
		}
		return fmt.Errorf("segment %q traverses non-object shape", name)
	}
	return fmt.Errorf("field %q does not exist", name)
}

func pointerFloats(values ...*float64) []float64 {
	result := make([]float64, 0, len(values))
	for _, value := range values {
		if value != nil {
			result = append(result, *value)
		}
	}
	return result
}

func shapeHasConstraints(shape typedValueShape) bool {
	switch value := shape.(type) {
	case typedStringShape:
		return len(value.Enum) > 0 || value.Format != "" || value.MinLength != nil || value.MaxLength != nil

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Fix the override Path so every intermediate segment names an object-typed (or oneOf-of-objects) field.
  2. If the intermediate field is an array, target the array field itself (e.g. "/items") instead of descending into it.
  3. Update the override after a data-model refactor that turned the nested struct into a scalar or slice.

Example fix

// before
common.TypedDataField{Path: "/owner/name", Description: "Owner"} // owner is a string
// after
common.TypedDataField{Path: "/owner", Description: "Owner name"}
Defensive patterns

Strategy: validation

Validate before calling

func pathTraversesObjects(path string, root map[string]common.TypedValueField) error {
  parts := strings.Split(strings.TrimPrefix(path, "/"), "/")
  cur := root
  for _, p := range parts[:len(parts)-1] {
    f, ok := cur[p]
    if !ok { return fmt.Errorf("missing %q", p) }
    obj, ok := f.Shape.(common.TypedObjectShape)
    if !ok { return fmt.Errorf("segment %q is not an object", p) }
    cur = fieldMap(obj)
  }
  _, ok := cur[parts[len(parts)-1]]
  if !ok { return fmt.Errorf("leaf %q missing", parts[len(parts)-1]) }
  return nil
}

Type guard

func isObjectShape(s common.TypedValueShape) bool { _, ok := s.(common.TypedObjectShape); return ok }

Prevention

When it happens

Trigger: CompileCommandDefinition with Output.Data.Overrides[i].Path such as "/items/0/name" or "/tags/inner" where "items" or "tags" is an array, string, number, or other non-object/non-oneOf shape, so a middle pointer segment cannot be traversed.

Common situations: Hand-writing a JSON pointer against the Go data struct and mistaking an array-of-objects for an object; the data model changed a nested struct into a slice or scalar while overrides still used the old deep path.

Related errors


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