{"record":{"id":"aab26598f8d9f34f","repo":"crowdsecurity/crowdsec","slug":"jsonextracttype-expected-type-s-for-target-s-bu","errorCode":null,"errorMessage":"jsonExtractType: expected type %s for target %s but found %s","messagePattern":"jsonExtractType: expected type (.+?) for target (.+?) but found (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/exprhelpers/jsonextract.go","lineNumber":106,"sourceCode":"\n\tlog.Tracef(\"extract path %+v\", fullpath)\n\n\tvalue, dataType, _, err := jsonparser.Get(\n\t\tjsonparser.StringToBytes(jsblob),\n\t\tfullpath...,\n\t)\n\tif err != nil {\n\t\tif errors.Is(err, jsonparser.KeyPathNotFoundError) {\n\t\t\tlog.Debugf(\"Key %+v doesn't exist\", target)\n\t\t\treturn nil, fmt.Errorf(\"key %s does not exist\", target)\n\t\t}\n\t\tlog.Errorf(\"jsonExtractType : %s : %s\", target, err)\n\t\treturn nil, fmt.Errorf(\"jsonExtractType: %s : %w\", target, err)\n\t}\n\n\tif dataType != t {\n\t\tlog.Errorf(\"jsonExtractType : expected type %s for target %s but found %s\", t, target, dataType.String())\n\t\treturn nil, fmt.Errorf(\"jsonExtractType: expected type %s for target %s but found %s\", t, target, dataType.String())\n\t}\n\n\treturn value, nil\n}\n\n// func JsonExtractSlice(jsblob string, target string) []interface{} {\nfunc JsonExtractSlice(params ...any) (any, error) {\n\tjsblob := params[0].(string)\n\ttarget := params[1].(string)\n\n\tvalue, err := jsonExtractType(jsblob, target, jsonparser.Array)\n\tif err != nil {\n\t\tlog.Errorf(\"JsonExtractSlice : %s\", err)\n\t\treturn []interface{}(nil), nil\n\t}\n\n\ts := make([]interface{}, 0)\n","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/exprhelpers/jsonextract.go#L88-L124","documentation":"jsonExtractType enforces the expected jsonparser.ValueType: JsonExtractSlice requires Array and JsonExtractObject requires Object. If the key path exists but holds a different type (string, number, null...), extraction fails with this message naming expected vs actual type.","triggerScenarios":"Calling JsonExtractSlice on a key that holds a string or object, or JsonExtractObject on a key holding an array/scalar/null; upstream field type changed between payload versions.","commonSituations":"API/schema drift where 'targets' becomes a string or 'details' becomes null; indexing a JSON field that is sometimes an array and sometimes a single object.","solutions":["Confirm the actual type at that path in a sample payload and use the matching extractor (JsonExtractSlice vs JsonExtractObject)","Treat null/absent-type cases explicitly before extraction (null dataType is a common mismatch)","Add schema validation upstream so type changes are caught early","Handle the error and return an empty slice/object instead of failing the expression"],"exampleFix":"// before: expects array but field may be object\nvals, err := JsonExtractSlice(evt, \"items\")\n// after: fall back on type error\nvals, err := JsonExtractSlice(evt, \"items\")\nif err != nil {\n    obj, oerr := JsonExtractObject(evt, \"items\")\n    if oerr != nil { return []interface{}{}, nil }\n    vals = []interface{}{obj}\n}","handlingStrategy":"fallback","validationCode":"// no cheap pre-check via public API; validate shape with encoding/json\nvar probe any\nif err := json.Unmarshal([]byte(jsblob), &probe); err == nil {\n    if v, ok := dig(probe, target); ok {\n        if _, isArr := v.([]any); !isArr {\n            return errors.New(\"target is not an array\")\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"vals, err := exprhelpers.JsonExtractSlice(jsblob, target)\nif err != nil && strings.Contains(err.Error(), \"but found\") {\n    // type drift: fall back to tolerant extraction\n    return []interface{}{}, nil\n}","preventionTips":["Pin extractor choice to the documented schema per source type","Plan for upstream type changes (object vs array vs null)","Prefer JsonExtract (tolerant) when the type may vary","Alert on 'expected type ... but found' log lines — they signal schema drift"],"tags":["go","json","type-mismatch","schema"],"backgroundTag":"shape-mismatch","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}