infiniflow/ragflow · error · Exception
Can't find variable: '{cpn_id}@{var_nm}'
Error message
Can't find variable: '{cpn_id}@{var_nm}' What it means
When the canvas resolves a variable reference of the form '{component_id@output.param.path}', it looks up the source component by id. If no component with that id exists in the DSL, this Exception is raised during get_variable_value — the reference points at a deleted or renamed node.
Source
Thrown at agent/canvas.py:255
last = m.end()
out_parts.append(value[last:])
return "".join(out_parts)
def get_variable_value(self, exp: str) -> Any:
exp = exp.strip("{").strip("}").strip(" ").strip("{").strip("}")
if exp.find("@") < 0:
return self.globals[exp]
# Split from the left with maxsplit=1 so the trailing var_nm can
# legitimately contain '@' characters (defensive: although the
# upstream regex in `get_value_with_variable` constrains `var_nm`
# to `[A-Za-z0-9_.-]+`, direct callers of this method may pass
# any string and should not raise `ValueError: too many values
# to unpack`). `cpn_id` is system-generated and never contains '@'.
cpn_id, var_nm = exp.split("@", 1)
cpn = self.get_component(cpn_id)
if not cpn:
raise Exception(f"Can't find variable: '{cpn_id}@{var_nm}'")
parts = var_nm.split(".", 1)
root_key = parts[0]
rest = parts[1] if len(parts) > 1 else ""
root_val = cpn["obj"].output(root_key)
if not rest:
return root_val
return self.get_variable_param_value(root_val, rest)
def get_variable_param_value(self, obj: Any, path: str) -> Any:
cur = obj
if not path:
return cur
for key in path.split("."):
if cur is None:
return None
if isinstance(cur, str):View on GitHub (pinned to 554fb1133a)
Solutions
- Open the canvas and find the node whose param still references the deleted component id; rebind it to an existing component or delete the stale reference.
- Search the DSL JSON for the cpn_id shown in the error to locate every stale reference.
- If copy-pasting between workflows, re-wire the pasted node's references to components that exist in the target canvas.
- Add a lint pass over the DSL (all '@' references resolve to existing component ids) before running.
Example fix
# before
params = {"content": "{deadbeef@output.text}"} # deadbeef was deleted
# after
params = {"content": "{live1234@output.text}"} # rebind to existing node Defensive patterns
Strategy: validation
Validate before calling
def check_references(dsl):
ids = set(dsl['components'].keys())
bad = []
for k, cpn in dsl['components'].items():
for v in extract_refs(cpn['obj'].get('params', {})): # finds '{id@...}' tokens
if v.split('@', 1)[0] not in ids:
bad.append((k, v))
return bad # empty list == safe Type guard
def ref_resolves(exp: str, component_ids: set) -> bool:
return '@' not in exp or exp.strip('{} ').split('@', 1)[0] in component_ids Try / catch
try:
value = canvas.get_variable_value(exp)
except Exception as e:
if str(e).startswith("Can't find variable:"):
# stale reference: surface which node/param held it and fail fast
raise WorkflowIntegrityError(str(e)) from e
raise Prevention
- Run a reference-lint pass over the DSL after every node deletion.
- When deleting nodes, let the editor remove inbound references atomically.
- Never hand-type component ids in reference expressions; pick from the variable picker.
When it happens
Trigger: Any component param containing a reference like '{abc123@output.text}' where 'abc123' is not a key in dsl['components'] — typical after deleting a node that other nodes still reference, or hand-editing component ids.
Common situations: Deleting an upstream component without cleaning references to it; copy-pasting nodes between canvases (ids don't travel with valid targets); race where the canvas is edited while a run is starting; typos in manually written reference expressions.
Related errors
- {component_name}: {e}
- Param define nesting too deep!!!, can not parse it
- cpn `{name}` has redundant parameters: `{[redundant_attrs]}`
- Please check runtime conf, {} = {} does not match user-param
- {} not supported, should be string type
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/df71155fce53a295.
Report an issue: GitHub.