unclecode/crawl4ai · error · ValueError

Unknown procedure {c.args[0]!r}

Error message

Unknown procedure {c.args[0]!r}

What it means

ValueError from the C4A-Script compiler's _inline_calls pass: a CALL command references a procedure name that was never defined by a PROC declaration in the compiled source (including its includes). Since procedures are inlined by name lookup in self.procs, an unknown name cannot be resolved.

Source

Thrown at crawl4ai/script/c4ai_script.py:367

                p=(self.root/c.args[0]).resolve()
                if p in seen: raise ValueError(f"Circular include {p}")
                seen.add(p); out+=self._parse_with_includes(p.read_text(),seen)
            else: out.append(c)
        return out

    def _collect_procs(self,ir):
        out=[]
        for i in ir:
            if isinstance(i,Proc): self.procs[i.name]=i
            else: out.append(i)
        return out

    def _inline_calls(self,ir):
        out=[]
        for c in ir:
            if isinstance(c,Cmd) and c.op=="CALL":
                if c.args[0] not in self.procs:
                    raise ValueError(f"Unknown procedure {c.args[0]!r}")
                out+=self._inline_calls(self.procs[c.args[0]].body)
            else: out.append(c)
        return out

    def _apply_set_vars(self,ir):
        def sub(s): return re.sub(r"\$(\w+)",lambda m:str(self.vars.get(m.group(1),m.group(0))) ,s) if isinstance(s,str) else s
        out=[]
        for c in ir:
            if isinstance(c,Cmd):
                if c.op=="SETVAR":
                    # Store variable
                    self.vars[c.args[0].lstrip('$')]=c.args[1]
                else:
                    # Apply variable substitution to commands that use them
                    if c.op in("TYPE","EVAL","SET"): c.args=[sub(a) for a in c.args]
                    out.append(c)
        return out

View on GitHub (pinned to 7e80152142)

Solutions

  1. Define the missing PROC in the script or in an included file.
  2. Check spelling and case of the procedure name at both definition and call site.
  3. Ensure the file declaring the procedure is INCLUDEd from the entry script (and not part of an include cycle that failed earlier).
  4. Run validate()/compile_string() in CI to catch unknown procedures before runtime.

Example fix

# before
CALL "extract_rows"   # ValueError: Unknown procedure 'extract_rows'

# after
PROC extract_pages {
  EXTRACT css="table tr"
}
CALL "extract_pages"
Defensive patterns

Strategy: validation

Validate before calling

import re

def all_calls_defined(script_text: str) -> list[str]:
    defined = set(re.findall(r"PROC\s+(\w+)", script_text))
    called = set(re.findall(r"CALL\s+[\"']?(\w+)[\"']?", script_text))
    return sorted(called - defined)  # empty list = OK

Try / catch

try:
    js = compile_string(script)
except ValueError as e:
    if 'Unknown procedure' in str(e):
        undefined = all_calls_defined('\n'.join(script))
        raise ValueError(f"Define or fix: {undefined}") from e

Prevention

When it happens

Trigger: Writing CALL "do_thing" when no PROC do_thing exists, misspelling a procedure name (case-sensitive), or defining the procedure in a file that is not INCLUDEd into the compiled script.

Common situations: Renaming a PROC but forgetting call sites, copy-pasting scripts that reference procedures from another file, typos, or case mismatches (DoThing vs dothing).

Related errors


AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14). Data as JSON: /api/errors/674db0310a28e08a. Report an issue: GitHub.