cap_grant_exceeded: the program reaches a capability main was not granted

main’s capability parameters are the program’s grant: everything the program can do, through any chain of calls, must fit inside it. This error points at a use (a builtin call) that needs a capability outside the grant, and labels each call on the way from main to it. A module’s needs line does not raise the grant; it only declares what that module’s code may use.

A program that triggers it

mod Main do
  needs IO.Console
  needs IO.FileWrite

  fn save(n : Int) : () do
    let _ = file_write("/tmp/count", int_to_string(n))
    ()
  end

  fn main(_c : Cap(IO.Console)) do
    save(1)
    println("saved")
  end
end

The fix

Grant main the capability too, by adding a parameter for it (or remove the use):

mod Main do
  needs IO.Console
  needs IO.FileWrite

  fn save(n : Int) : () do
    let _ = file_write("/tmp/count", int_to_string(n))
    ()
  end

  fn main(_c : Cap(IO.Console), _fw : Cap(IO.FileWrite)) do
    save(1)
    println("saved")
  end
end

Why the rule exists

The grant on main is what the person running the program agrees to. Reading main’s signature tells them the most the program can do, so a program that writes files must say so there, however deep the write is.

See also: the language reference.