unclecode/crawl4ai · error · ValueError

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

Error message

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

What it means

ValueError from the JS-emission stage (_handle_cmd_or_proc) of the C4A-Script compiler: it encounters a CALL to a procedure absent from self.procs while emitting JavaScript. This duplicates the earlier _inline_calls check as a defensive guard at emit time.

Source

Thrown at crawl4ai/script/c4ai_script.py:612

        if cond_type == "EXISTS":
            return f"!!document.querySelector('{condition[1]}')"
        elif cond_type == "NOT":
            # Recursively handle the negated condition
            inner_condition = self._emit_condition(condition[1])
            return f"!({inner_condition})"
        else:  # JS condition
            return condition[1]
    
    def _handle_cmd_or_proc(self, cmd):
        """Handle a command that might be a regular command or a procedure call"""
        if not cmd:
            return ""
        
        if isinstance(cmd, Cmd):
            if cmd.op == "CALL":
                # Inline the procedure
                if cmd.args[0] not in self.procs:
                    raise ValueError(f"Unknown procedure {cmd.args[0]!r}")
                proc_body = self.procs[cmd.args[0]].body
                return "\n".join([self._emit_js(c) for c in proc_body if c.op != "NOP"])
            else:
                return self._emit_js(cmd)
        return ""

# --------------------------------------------------------------------------- #
# 5. Helpers + demo
# --------------------------------------------------------------------------- #

def compile_string(script: Union[str, List[str]], *, root: Union[pathlib.Path, None] = None) -> List[str]:
    """Compile C4A-Script from string or list of strings to JavaScript.
    
    Args:
        script: C4A-Script as a string or list of command strings
        root: Root directory for resolving includes (optional)
    
    Returns:

View on GitHub (pinned to 7e80152142)

Solutions

  1. If writing scripts normally, fix the root cause as for any unknown procedure: define the PROC or correct its name.
  2. Prefer the public compile_string()/compile() entry points instead of driving internal passes yourself.
  3. If manipulating IR programmatically, run _collect_procs before _inline_calls/emit so every PROC is registered.
  4. Ensure includes carrying PROC definitions are present in the parsed source.

Example fix

# before
js = compile_string(["CALL 'do_thing'"])  # ValueError: Unknown procedure 'do_thing'

# after
js = compile_string([
    "PROC do_thing {",
    "  CLICK 'button#go'",
    "}",
    "CALL 'do_thing'",
])
Defensive patterns

Strategy: validation

Try / catch

try:
    js_lines = compile_string(script_lines, root=root)
except ValueError as e:
    if 'Unknown procedure' in str(e):
        # define the PROC or fix its name, then recompile
        raise

Prevention

When it happens

Trigger: Normally unreachable because _inline_calls already resolves or rejects every CALL — but can fire when the IR is manipulated between passes, when a Proc is added after collection, or when using the emitter on hand-constructed command lists.

Common situations: Programmatic use of compiler internals (building Cmd lists manually), version skew between cached/partial IR and the emitter, or subclass overrides that reorder passes.

Related errors


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