How to Fix: cli: unable to `–invoke` a function with arguments

5 min read

Wasmtime CLI --invoke Fails When Calling a Function With Arguments: Root Cause and Fix

The failure is not in the WebAssembly module. The bug happens because the Wasmtime CLI invocation path historically handled exported function calls in a way that did not correctly parse or forward typed positional arguments for --invoke, especially when calling a function that expects parameters like i32.

Reproducing the Problem

Given this minimal WebAssembly Text module:

(module
  (func (export "foo") (param $a i32) (result i32)
    (local.get $a)))

The exported function foo accepts one 32-bit integer and returns that same value.

A typical expectation is that the following style of command should work:

wasmtime run module.wat --invoke foo 1

But on affected versions, the CLI can reject the invocation, ignore the argument, or fail during argument handling before the function is actually executed.

Understanding the Root Cause

The core issue is a mismatch between CLI argument parsing and WebAssembly function signature handling.

When --invoke is used, the CLI must do all of the following correctly:

  • Load the module and find the exported function by name.
  • Inspect the function signature to determine expected parameter types.
  • Parse command-line values such as 1 into the correct wasm value type, like i32.
  • Pass those converted values into the runtime invocation API in the correct order.

In the buggy implementation, one or more of those steps was incomplete for command-line invocation with function arguments. The result is that a valid module like:

(func (export "foo") (param $a i32) (result i32) ...)

was treated as though it were either:

  • a function with no parameters,
  • a function whose parameters were not parseable from CLI input, or
  • a target whose trailing command-line arguments were being consumed by the wrong parser branch.

Technically, this is a frontend CLI integration bug, not a WebAssembly validation problem. The module is valid, the export is valid, and the function signature is valid. The failure happens at the boundary where the CLI translates shell arguments into typed runtime values.

Step-by-Step Solution

The correct fix is to ensure the CLI invocation flow supports argument-bearing exports and converts user input into the exact value types expected by the target function.

1. Confirm the module export and signature

Start with the smallest possible test case:

(module
  (func (export "foo") (param $a i32) (result i32)
    (local.get $a)))

Save it as module.wat.

2. Verify whether your Wasmtime version contains the bug

Run:

wasmtime --version

If you are working from source, also test your local build directly:

target/debug/wasmtime --version

If the version is older or matches a known broken revision around this issue, proceed with an update or patch.

3. Rebuild or upgrade Wasmtime

If you use the project from source:

git pull
cargo build

Then retry:

target/debug/wasmtime run --disable-cache module.wat --invoke foo 1

If you use an installed binary, upgrade to a release that includes the CLI fix.

4. Ensure the CLI parses arguments after --invoke

The invocation logic should conceptually behave like this:

1. Read export name after --invoke
2. Collect remaining positional values as function arguments
3. Inspect the export signature
4. Convert each CLI string to the matching wasm type
5. Call the function with typed values
6. Print the result

If you are implementing the fix in the CLI codebase, verify these conditions:

  • The parser does not stop after reading the export name.
  • Remaining arguments are preserved instead of being interpreted as unrelated CLI options.
  • The target export is resolved as a function export, not just any export.
  • Each raw string argument is converted according to the function signature, such as i32, i64, f32, or f64.
  • The number of provided arguments matches the function arity.

5. Example of expected successful behavior

With the bug fixed, this invocation should return 1:

target/debug/wasmtime run --disable-cache module.wat --invoke foo 1

You can also validate with another value:

target/debug/wasmtime run --disable-cache module.wat --invoke foo 42

Expected output:

42

6. Add a regression test

This issue should be protected with a regression test so future CLI refactors do not break typed invocation again.

# Pseudocode test expectation
module = r#"
(module
  (func (export \"foo\") (param i32) (result i32)
    local.get 0))
"#

run_cli(["run", "module.wat", "--invoke", "foo", "7"])
assert stdout == "7"

A good regression test also checks:

  • wrong argument count,
  • wrong argument type,
  • non-function export names,
  • multi-parameter functions.

Common Edge Cases

1. Argument count mismatch

If the exported function expects one parameter and you provide zero or two, the CLI should fail with a clear error.

(func (export "foo") (param i32) (result i32) ...)

Bad calls:

wasmtime run module.wat --invoke foo
wasmtime run module.wat --invoke foo 1 2

2. Type conversion failures

A string like abc cannot be parsed as i32. The CLI should report a type parsing error, not a generic runtime failure.

wasmtime run module.wat --invoke foo abc

3. Invoking a non-function export

If the export name refers to a memory, global, or table instead of a function, the CLI must reject it explicitly.

4. Negative integers and numeric bounds

Values such as -1 should work for signed integer parameters if the parser supports the target type correctly. Out-of-range values for i32 should fail before invocation.

5. Multiple parameters

Once single-argument invocation works, verify ordering is preserved:

(module
  (func (export "add") (param i32 i32) (result i32)
    local.get 0
    local.get 1
    i32.add))
wasmtime run add.wat --invoke add 20 22

Expected result:

42

6. Shell quoting behavior

Some failures can look like Wasmtime bugs when they are actually caused by the shell splitting or rewriting arguments. Always test with simple numeric literals first.

FAQ

Why does this fail when the WebAssembly module itself is valid?

Because the problem is in the CLI layer, not in module validation. Wasmtime can load the module, but the command-line path may fail when converting user-supplied arguments into typed values for --invoke.

Is this specific to i32 parameters?

No. i32 is just the smallest reproduction. Any exported function that requires parameter parsing can be affected if the CLI does not correctly map strings to wasm value types.

What is the best long-term fix?

The best fix is to update the CLI implementation so it introspects the export signature, validates arity, parses each argument into the correct type, and adds regression tests for argument-bearing invocations. Upgrading to a version that includes that fix is the safest path for users.

If you are documenting the issue internally, describe it as: Wasmtime CLI --invoke did not correctly support passing typed function arguments to exported WebAssembly functions.

Leave a Reply

Your email address will not be published. Required fields are marked *