Skip to content
Latchkey

dune .mli / .ml signature mismatch (unbound in signature) in CI

When an .mli mentions a type or value the .ml does not (or no longer) defines, the module cannot be sealed against its interface. CI fails deterministically wherever the two files disagree.

What this error means

dune build fails with "Error: Unbound type constructor X" or "The value X is required but not provided" pointing at the .mli, after the implementation changed.

dune
File "lib/api.mli", line 4, characters 15-20:
4 | val fetch : query -> result
                   ^^^^^
Error: Unbound type constructor query

Common causes

The interface references a removed type or value

The .mli still names something the .ml deleted or renamed, so the signature cannot be satisfied.

A type moved without updating the interface

A type definition moved to another module but the .mli still expects it locally.

How to fix it

Sync the interface to the implementation

  1. Read which type or value the .mli references that is missing.
  2. Restore or re-expose it in the .ml, or remove it from the .mli.
  3. Rebuild to confirm the interface seals.
lib/api.ml
(* re-add the type the mli expects, or drop the val from the mli *)
type query = { q : string }

Regenerate the interface as a baseline

Let dune print the inferred signature so you can compare it against the committed .mli.

Terminal
dune build @check
ocaml-print-intf lib/api.ml

How to prevent it

  • Change .mli and .ml in the same commit for public edits.
  • Keep types the interface exposes defined in the same module.
  • Build the check alias locally before pushing.

Frequently asked questions

What causes ".mli / .ml drift"?
The .mli still names something the .ml deleted or renamed, so the signature cannot be satisfied.
How do I fix .mli / .ml drift?
Sync the interface to the implementation

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card