{"record":{"id":"2cd827b8b6654843","repo":"infiniflow/ragflow","slug":"invoke-headers-must-be-a-json-object","errorCode":null,"errorMessage":"Invoke headers must be a JSON object.","messagePattern":"Invoke headers must be a JSON object\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/component/invoke.py","lineNumber":190,"sourceCode":"                self.set_input_value(para[\"ref\"], value)\n        return args\n\n    def _build_url(self, kwargs: dict) -> str:\n        url = self._resolve_template_text(self._param.url.strip(), kwargs)\n        if not url.startswith((\"http://\", \"https://\")):\n            url = \"http://\" + url\n        hostname, ip = assert_url_is_safe(url)\n        self._pinned_hostname = hostname\n        self._pinned_ip = ip\n        return url\n\n    def _build_headers(self, kwargs: dict) -> dict:\n        if not self._param.headers:\n            return {}\n\n        headers = json.loads(self._param.headers)\n        if not isinstance(headers, dict):\n            raise ValueError(\"Invoke headers must be a JSON object.\")\n\n        return {key: self._resolve_header_text(value, kwargs) if isinstance(value, str) else value for key, value in headers.items()}\n\n    @staticmethod\n    def _ssrf_log_target(url: str) -> str:\n        parsed = urlparse(url)\n        if not parsed.scheme or not parsed.hostname:\n            return \"invalid-url\"\n        return f\"{parsed.scheme}://{parsed.hostname}\"\n\n    def _normalize_proxy_url(self) -> str | None:\n        proxy = (self._param.proxy or \"\").strip()\n        if not re.sub(r\"https?:?/?/?\", \"\", proxy):\n            return None\n        if not proxy.startswith((\"http://\", \"https://\")):\n            proxy = \"http://\" + proxy\n        return proxy\n","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/component/invoke.py#L172-L208","documentation":"Thrown while building HTTP headers for the Invoke component. The configured headers string is parsed with json.loads and must deserialize to a JSON object (Python dict); any other top-level JSON type (array, string, number, boolean) triggers this ValueError.","triggerScenarios":"Setting the Invoke component's headers parameter to a JSON array like '[\"Authorization: Bearer x\"]' or a bare string like '\"Authorization: Bearer x\"' instead of an object. Note that malformed JSON raises json.JSONDecodeError earlier; this error is specifically valid-JSON-but-wrong-shape.","commonSituations":"Copying cURL-style header lines into the headers field; pasting a header list produced by browser devtools 'copy as JSON'; templates that emit a list of {name, value} pairs.","solutions":["Change the headers configuration to a flat JSON object: {\"Authorization\": \"Bearer {{token}}\", \"Content-Type\": \"application/json\"}.","If you copied [{\"name\":\"...\",\"value\":\"...\"}] pairs, flatten them into a single object with name as key and value as value.","Validate the headers string with json.loads in a scratch step before saving the component."],"exampleFix":"# before (list of pairs)\n\"headers\": \"[{\\\"name\\\": \\\"X-Api-Key\\\", \\\"value\\\": \\\"123\\\"}]\"\n\n# after (JSON object)\n\"headers\": \"{\\\"X-Api-Key\\\": \\\"123\\\"}\"","handlingStrategy":"validation","validationCode":"import json\n\ndef valid_headers(cfg: str) -> bool:\n    try:\n        return isinstance(json.loads(cfg), dict) if cfg else True\n    except json.JSONDecodeError:\n        return False","typeGuard":"import json\n\ndef headers_is_object(cfg: str) -> bool:\n    if not cfg:\n        return True\n    try:\n        return isinstance(json.loads(cfg), dict)\n    except json.JSONDecodeError:\n        return False","tryCatchPattern":"try:\n    headers = json.loads(param_headers)\nexcept json.JSONDecodeError:\n    raise ValueError('Invoke headers is not valid JSON') from None\nif not isinstance(headers, dict):\n    raise ValueError('Invoke headers must be a JSON object.')","preventionTips":["Always author headers as a flat JSON object, never a list of pairs or a bare string.","Validate headers with json.loads + isinstance(dict) when generating/saving canvas configurations.","Use template variables (e.g. \"Bearer {{token}}\") only as header VALUES, not as structural parts of the JSON."],"tags":["json","http-headers","invoke-component","configuration"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}