{"record":{"id":"c3393954dd1059bd","repo":"infiniflow/ragflow","slug":"invoke-json-argument-key-is-not-json-serializa","errorCode":null,"errorMessage":"Invoke JSON argument '{key}' is not JSON-serializable.","messagePattern":"Invoke JSON argument '(.+?)' is not JSON-serializable\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/component/invoke.py","lineNumber":96,"sourceCode":"                logging.info(\n                    \"Invoke JSON arg coercion skipped; value is not valid JSON. key=%s raw=%r error=%s\",\n                    key,\n                    raw_value,\n                    exc,\n                )\n                return raw_value\n\n        try:\n            json.dumps(value, allow_nan=False)\n        except (TypeError, ValueError) as exc:\n            logging.warning(\n                \"Invoke JSON arg is not JSON-serializable. key=%s value_type=%s value=%r error=%s\",\n                key,\n                type(value).__name__,\n                value,\n                exc,\n            )\n            raise ValueError(f\"Invoke JSON argument '{key}' is not JSON-serializable.\") from exc\n\n        return value\n\n    def get_input_form(self) -> dict[str, dict]:\n        res = {}\n        for item in self._param.variables or []:\n            if not isinstance(item, dict):\n                continue\n            ref = (item.get(\"ref\") or \"\").strip()\n            if not ref or ref in res:\n                continue\n\n            elements = self.get_input_elements_from_text(\"{\" + ref + \"}\")\n            element = elements.get(ref, {})\n            res[ref] = {\n                \"type\": \"line\",\n                \"name\": element.get(\"name\") or item.get(\"key\") or ref,\n            }","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/component/invoke.py#L78-L114","documentation":"Thrown by the Invoke component when validating an argument passed as JSON. Before sending the request, the component runs json.dumps(value, allow_nan=False) on each argument; if the value cannot be serialized (TypeError) or contains NaN/Infinity (ValueError, because allow_nan=False), the argument is rejected. The original exception is chained, and a warning with the key, value type, and repr is logged.","triggerScenarios":"Calling an Invoke component whose variables resolve to a non-JSON value: a datetime/date object, set, bytes, numpy scalar, or an ORM/model instance; or a float that is NaN/Inf (allow_nan=False makes even json.dumps itself raise ValueError). The failure occurs at argument-validation time, before any HTTP request is made.","commonSituations":"Upstream component (e.g. Code, Iteration, LLM returning structured output parsed into Python objects) produces datetime or numpy types that flow into an Invoke argument; dividing float values that yield NaN; passing a Peewee model row instead of a plain dict.","solutions":["Convert the offending value to JSON-native types before it reaches Invoke: str()/isoformat() for datetimes, list() for sets, .item() for numpy scalars, dict(model) for ORM rows.","Check the preceding log line 'Invoke JSON arg is not JSON-serializable. key=... value_type=... value=...' to identify exactly which key and type failed, then fix that variable's producer.","If NaN/Infinity is legitimate in your data, sanitize it explicitly (e.g. replace with None) because the component forbids non-finite floats by design.","Add a Code/transform component between the producer and Invoke that normalizes the payload to plain dict/list/str/int/float/bool/None."],"exampleFix":"# before\ninvoke_args = {\"ts\": created_at, \"tags\": {\"a\", \"b\"}}  # datetime + set -> raises\n\n# after\ninvoke_args = {\n    \"ts\": created_at.isoformat() if created_at else None,\n    \"tags\": sorted({\"a\", \"b\"}),\n}","handlingStrategy":"validation","validationCode":"import json, math\n\ndef json_safe(value):\n    try:\n        json.dumps(value, allow_nan=False)\n        return True\n    except (TypeError, ValueError):\n        return False\n\n# before wiring args into Invoke:\nassert all(json_safe(v) for v in invoke_args.values()), invoke_args.keys()","typeGuard":"import json\n\ndef is_json_serializable(v) -> bool:\n    try:\n        json.dumps(v, allow_nan=False)\n        return True\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":"try:\n    invoke_component._invoke(**kwargs)\nexcept ValueError as e:\n    if 'not JSON-serializable' in str(e):\n        # normalize the offending variable and retry once\n        ...","preventionTips":["Normalize upstream outputs (datetime -> isoformat, set -> list, numpy -> .item()) in a Code component before Invoke.","Never feed floats that can be NaN/Inf into JSON arguments; replace with None explicitly.","Log key and type when serialization fails so the offending producer is identifiable."],"tags":["json","serialization","invoke-component","agent-canvas"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}