infiniflow/ragflow · error · ValueError
Invoke headers must be a JSON object.
Error message
Invoke headers must be a JSON object.
What it means
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.
Source
Thrown at agent/component/invoke.py:190
self.set_input_value(para["ref"], value)
return args
def _build_url(self, kwargs: dict) -> str:
url = self._resolve_template_text(self._param.url.strip(), kwargs)
if not url.startswith(("http://", "https://")):
url = "http://" + url
hostname, ip = assert_url_is_safe(url)
self._pinned_hostname = hostname
self._pinned_ip = ip
return url
def _build_headers(self, kwargs: dict) -> dict:
if not self._param.headers:
return {}
headers = json.loads(self._param.headers)
if not isinstance(headers, dict):
raise ValueError("Invoke headers must be a JSON object.")
return {key: self._resolve_header_text(value, kwargs) if isinstance(value, str) else value for key, value in headers.items()}
@staticmethod
def _ssrf_log_target(url: str) -> str:
parsed = urlparse(url)
if not parsed.scheme or not parsed.hostname:
return "invalid-url"
return f"{parsed.scheme}://{parsed.hostname}"
def _normalize_proxy_url(self) -> str | None:
proxy = (self._param.proxy or "").strip()
if not re.sub(r"https?:?/?/?", "", proxy):
return None
if not proxy.startswith(("http://", "https://")):
proxy = "http://" + proxy
return proxy
View on GitHub (pinned to 554fb1133a)
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.
Example fix
# before (list of pairs)
"headers": "[{\"name\": \"X-Api-Key\", \"value\": \"123\"}]"
# after (JSON object)
"headers": "{\"X-Api-Key\": \"123\"}" Defensive patterns
Strategy: validation
Validate before calling
import json
def valid_headers(cfg: str) -> bool:
try:
return isinstance(json.loads(cfg), dict) if cfg else True
except json.JSONDecodeError:
return False Type guard
import json
def headers_is_object(cfg: str) -> bool:
if not cfg:
return True
try:
return isinstance(json.loads(cfg), dict)
except json.JSONDecodeError:
return False Try / catch
try:
headers = json.loads(param_headers)
except json.JSONDecodeError:
raise ValueError('Invoke headers is not valid JSON') from None
if not isinstance(headers, dict):
raise ValueError('Invoke headers must be a JSON object.') Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invoke JSON argument '{key}' is not JSON-serializable.
- 101
- main() returned a non-JSON-serializable value.
- WhatsApp session is not running.
- main() must return a value. Use null for an empty result.
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/2cd827b8b6654843.
Report an issue: GitHub.