larksuite/cli · error

json pointer %q: value at %q is %T, not an object

Error message

json pointer %q: value at %q is %T, not an object

What it means

JSON Pointer traversal in this implementation only descends through objects (map[string]interface{}). If, mid-path, the current value is not an object (a string, number, bool, array, or nil), the traversal cannot continue and reports the Go type found at the traversed prefix.

Source

Thrown at internal/binding/json_pointer.go:44

	if !strings.HasPrefix(pointer, "/") {
		return nil, fmt.Errorf("json pointer must start with '/' or be empty, got %q", pointer)
	}

	// Split after the leading "/" and decode each segment.
	segments := strings.Split(pointer[1:], "/")
	current := data

	for i, raw := range segments {
		// RFC 6901 unescaping: ~1 → /, ~0 → ~ (order matters).
		key, err := decodeJSONPointerSegment(raw)
		if err != nil {
			return nil, fmt.Errorf("json pointer %q: segment %q: %w", pointer, raw, err)
		}

		m, ok := current.(map[string]interface{})
		if !ok {
			traversed := "/" + strings.Join(segments[:i], "/")
			return nil, fmt.Errorf("json pointer %q: value at %q is %T, not an object",
				pointer, traversed, current)
		}

		val, exists := m[key]
		if !exists {
			return nil, fmt.Errorf("json pointer %q: key %q not found", pointer, key)
		}

		current = val
	}

	return current, nil
}

func decodeJSONPointerSegment(raw string) (string, error) {
	var out strings.Builder
	for i := 0; i < len(raw); i++ {
		if raw[i] != '~' {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Shorten the pointer so it stops at an object-valued key
  2. Inspect the JSON document and align the pointer with the real structure
  3. Do not use array-index segments — read the containing array value and index in caller code instead
  4. Re-unmarshal with map[string]interface{} handling if the data isn't a parsed map

Example fix

// before
ReadJSONPointer(data, "/accounts/app/id/inner")  // id is a string
// after
ReadJSONPointer(data, "/accounts/app/id")
Defensive patterns

Strategy: type-guard

Validate before calling

v, _ := ReadJSONPointer(data, trimmedPtr) // probe one level above
if _, ok := v.(map[string]interface{}); !ok {
    return fmt.Errorf("%q does not resolve to an object", trimmedPtr)
}

Type guard

func isObject(v interface{}) bool {
    _, ok := v.(map[string]interface{})
    return ok
}

Try / catch

val, err := binding.ReadJSONPointer(data, ptr)
if err != nil && strings.Contains(err.Error(), "not an object") {
    // inspect val type at the parent level; shorten ptr or index arrays manually
}

Prevention

When it happens

Trigger: Pointer like "/accounts/app/id/extra" where "/accounts/app/id" resolves to a string; indexing into an array (arrays are not supported here), or traversing past a scalar.

Common situations: Pointer written deeper than the actual document; trying array index segments ("/channels/0") which this implementation does not support; JSON shape changed (value became a scalar after a bridge upgrade).

Related errors


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