{"record":{"id":"9c436d11d2b12e94","repo":"larksuite/cli","slug":"json-pointer-q-value-at-q-is-t-not-an-object","errorCode":null,"errorMessage":"json pointer %q: value at %q is %T, not an object","messagePattern":"json pointer %q: value at %q is %T, not an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/binding/json_pointer.go","lineNumber":44,"sourceCode":"\tif !strings.HasPrefix(pointer, \"/\") {\n\t\treturn nil, fmt.Errorf(\"json pointer must start with '/' or be empty, got %q\", pointer)\n\t}\n\n\t// Split after the leading \"/\" and decode each segment.\n\tsegments := strings.Split(pointer[1:], \"/\")\n\tcurrent := data\n\n\tfor i, raw := range segments {\n\t\t// RFC 6901 unescaping: ~1 → /, ~0 → ~ (order matters).\n\t\tkey, err := decodeJSONPointerSegment(raw)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"json pointer %q: segment %q: %w\", pointer, raw, err)\n\t\t}\n\n\t\tm, ok := current.(map[string]interface{})\n\t\tif !ok {\n\t\t\ttraversed := \"/\" + strings.Join(segments[:i], \"/\")\n\t\t\treturn nil, fmt.Errorf(\"json pointer %q: value at %q is %T, not an object\",\n\t\t\t\tpointer, traversed, current)\n\t\t}\n\n\t\tval, exists := m[key]\n\t\tif !exists {\n\t\t\treturn nil, fmt.Errorf(\"json pointer %q: key %q not found\", pointer, key)\n\t\t}\n\n\t\tcurrent = val\n\t}\n\n\treturn current, nil\n}\n\nfunc decodeJSONPointerSegment(raw string) (string, error) {\n\tvar out strings.Builder\n\tfor i := 0; i < len(raw); i++ {\n\t\tif raw[i] != '~' {","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/binding/json_pointer.go#L26-L62","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Shorten the pointer so it stops at an object-valued key","Inspect the JSON document and align the pointer with the real structure","Do not use array-index segments — read the containing array value and index in caller code instead","Re-unmarshal with map[string]interface{} handling if the data isn't a parsed map"],"exampleFix":"// before\nReadJSONPointer(data, \"/accounts/app/id/inner\")  // id is a string\n// after\nReadJSONPointer(data, \"/accounts/app/id\")","handlingStrategy":"type-guard","validationCode":"v, _ := ReadJSONPointer(data, trimmedPtr) // probe one level above\nif _, ok := v.(map[string]interface{}); !ok {\n    return fmt.Errorf(\"%q does not resolve to an object\", trimmedPtr)\n}","typeGuard":"func isObject(v interface{}) bool {\n    _, ok := v.(map[string]interface{})\n    return ok\n}","tryCatchPattern":"val, err := binding.ReadJSONPointer(data, ptr)\nif err != nil && strings.Contains(err.Error(), \"not an object\") {\n    // inspect val type at the parent level; shorten ptr or index arrays manually\n}","preventionTips":["Keep pointers no deeper than the object structure of the document","Remember arrays are unsupported: index them in caller code after reading","Re-validate pointers whenever the JSON schema changes"],"tags":["json","rfc6901","type-error"],"backgroundTag":"invalid-json-pointer","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}