larksuite/cli · error

json pointer must start with '/' or be empty, got %q

Error message

json pointer must start with '/' or be empty, got %q

What it means

ReadJSONPointer implements RFC 6901 JSON Pointer traversal over a parsed JSON value. Per the spec, a pointer must be either the empty string (returns the whole document) or start with '/'. This error rejects any non-empty pointer lacking the leading slash before any traversal happens.

Source

Thrown at internal/binding/json_pointer.go:27

)

// ReadJSONPointer navigates a parsed JSON value (typically the result of
// json.Unmarshal into interface{}) using an RFC 6901 JSON Pointer string.
//
// Supported pointer format: "/key/subkey/subsubkey".
// An empty pointer ("") returns data as-is.
// RFC 6901 escape sequences: ~1 → /, ~0 → ~.
//
// Limitation: only object (map) traversal is supported. Array index segments
// (e.g., "/channels/0/appId") are not implemented because OpenClaw's
// SecretRef file provider uses object-only paths in practice.
func ReadJSONPointer(data interface{}, pointer string) (interface{}, error) {
	if pointer == "" {
		return data, nil
	}

	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)

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Prefix the pointer with '/': "accounts/app/id" not "accounts.app.id"
  2. Use the empty string "" when you want the entire document
  3. Trim whitespace and convert dot-separated paths to slash-separated segments

Example fix

// before
ReadJSONPointer(data, "accounts.app.id")
// after
ReadJSONPointer(data, "/accounts/app/id")
Defensive patterns

Strategy: validation

Validate before calling

func validPointer(p string) bool { return p == "" || strings.HasPrefix(p, "/") }
if !validPointer(ptr) {
    ptr = "/" + strings.ReplaceAll(strings.TrimLeft(ptr, "."), ".", "/")
}

Prevention

When it happens

Trigger: Calling ReadJSONPointer(data, "key") or "a.b" — any pointer that is neither "" nor starts with '/'.

Common situations: Users writing dot-notation ("accounts.app.id") or bare key names in a SecretRef path; config values copied from JSONPath; whitespace before the slash.

Related errors


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