E0118: tool_binding
E0118 tool_binding — a tool bound to a server ([mcp: …] / [openapi: …]) that soma.toml does not define, soma.lock does not pin, or whose declaration does not fit the pinned contract.
A compile-time error of soma check, the checker of the Soma programming language (soma explain E0118).
The rule
A tool bound to a server ([openapi: "pets/getPetById"] or [mcp: "docs"]) has no on handler: the server answers it, so its declaration must match the contract that soma tools sync pinned in soma.lock, and the server must be defined in soma.toml under [tools.<name>]. soma check compares the two offline and reports E0118 for a server soma.toml does not define, a tool soma.lock does not pin, or an argument the server does not take, of the wrong type, or left out. Parameter names are the server's, so pet_id must be written petId as the OpenAPI document declares it.
A program that triggers it
soma.toml
[package]
name = "petshop"
[tools.pets]
openapi = "petstore.json"
base_url = "https://petstore.example"wrong.cell
cell agent Clerk {
face {
signal describe_pet(id: Int) -> String
tool get_pet(pet_id: Int) -> Map [openapi: "pets/getPetById"] "Fetch a pet by id"
}
state job { initial: idle idle -> done }
on describe_pet(id: Int) {
let pet = get_pet(id)
let name = pet.name ?? "unknown"
return "pet {id}: {name}"
}
}What soma check prints:
$ soma check wrong.cell
error: tool 'get_pet' does not fit `getPetById` on `pets` as pinned in soma.lock: it declares `pet_id`, which the server's tool does not take (it takes petId: Int)
--> wrong.cell:4:9
|
4 | tool get_pet(pet_id: Int) -> Map [openapi: "pets/getPetById"…
| ^
= code: E0118
✗ 1 error(s), 0 warning(s).The fix field of soma check --json: tool 'get_pet' does not fit `getPetById` on `pets` as pinned in soma.lock: it declares `pet_id`, which the server's tool does not take (it takes petId: Int)
The fix
On line 4, tool get_pet(pet_id: Int) -> Map [openapi: "pets/getPetById"] "Fetch a pet by id" becomes tool get_pet(petId: Int) -> Map [openapi: "pets/getPetById"] "Fetch a pet by id".
wrong.cell → right.cell
--- wrong.cell
+++ right.cell
@@ -2,5 +2,5 @@
face {
signal describe_pet(id: Int) -> String
- tool get_pet(pet_id: Int) -> Map [openapi: "pets/getPetById"] "Fetch a pet by id"
+ tool get_pet(petId: Int) -> Map [openapi: "pets/getPetById"] "Fetch a pet by id"
}
state job { initial: idle idle -> done }With the fix, soma check accepts the program:
$ soma check right.cell
✓ All checks passed.