{"record":{"id":"513ffa8f08bd6cb0","repo":"crowdsecurity/crowdsec","slug":"invalid-type-for-headers-t","errorCode":null,"errorMessage":"invalid type for headers: %T","messagePattern":"invalid type for headers: %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/exprhelpers/http.go","lineNumber":128,"sourceCode":"}\n\n// HTTPRequest(method string, url string, headers map[string]any, body string) (*HTTPResponse, error)\nfunc HTTPRequest(params ...any) (any, error) {\n\tmethod, ok := params[0].(string)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid type for method: %T\", params[0])\n\t}\n\n\turi, ok := params[1].(string)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid type for url: %T\", params[1])\n\t}\n\n\t// headers is map[string]any so that expr map literals (map[string]interface{})\n\t// are accepted; values are stringified.\n\trawHeaders, ok := params[2].(map[string]any)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid type for headers: %T\", params[2])\n\t}\n\n\theaders := make(map[string]string, len(rawHeaders))\n\tfor k, v := range rawHeaders {\n\t\theaders[k] = fmt.Sprint(v)\n\t}\n\n\tbody, ok := params[3].(string)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid type for body: %T\", params[3])\n\t}\n\n\tvar reader io.Reader\n\tif body != \"\" {\n\t\treader = strings.NewReader(body)\n\t}\n\n\treturn doHTTPRequest(method, uri, headers, reader)","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/exprhelpers/http.go#L110-L146","documentation":"HTTPRequest is an expr-lang helper taking (method, url, headers map[string]any, body string). The headers argument must be a map[string]any (typically an expr map literal); any other Go type — map[string]string, nil, or a non-map — is rejected with this error before any request is made.","triggerScenarios":"Calling HTTPRequest with params[2] not of type map[string]any: passing a map[string]string literal, passing nil as headers, or passing an expr expression that evaluates to something other than a map (e.g. a slice or struct).","commonSituations":"Writing expr helper calls by hand and supplying headers as map[string]string (a common Go habit), forgetting the headers argument so nil is passed, or piping a parsed JSON object whose dynamic type isn't map[string]any.","solutions":["Pass headers as an expr map literal like {\"Content-Type\": \"application/json\"}, which produces map[string]any","If you have a map[string]string, rebuild it as map[string]any before calling HTTPRequest","Ensure all four arguments (method, url, headers, body) are provided so headers isn't a missing/nil param","Wrap header construction so non-map values are converted or defaulted to an empty map"],"exampleFix":"// before (map[string]string rejected)\nHTTPRequest(\"POST\", url, map[string]string{\"X-Token\": token}, \"\")\n// after\nHTTPRequest(\"POST\", url, {\"X-Token\": token}, \"\")","handlingStrategy":"type-guard","validationCode":"hdrs, ok := args[2].(map[string]any)\nif !ok {\n    return fmt.Errorf(\"headers must be a map[string]any, got %T\", args[2])\n}","typeGuard":"func isHeaderMap(v any) bool {\n    _, ok := v.(map[string]any)\n    return ok\n}","tryCatchPattern":"resp, err := exprhelpers.HTTPRequest(method, url, headers, body)\nif err != nil {\n    if strings.HasPrefix(err.Error(), \"invalid type for headers\") {\n        // fall back to default headers or skip request\n    }\n    return err\n}","preventionTips":["Always build headers as expr map literals: {\"K\": \"v\"}","Never pass map[string]string to expr HTTP helpers","Supply all four HTTPRequest arguments so params don't shift","Unit-test expr expressions with TestHTTPRequest-style calls before deploying"],"tags":["go","expr","http","type-mismatch"],"backgroundTag":"type-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"}