Resolving Unbound Module and Unbound Value Errors in OCaml with Dune
A diagnostic guide to fixing 'Unbound module' and 'Unbound value' errors in OCaml. Learn how to audit Dune configurations, resolve naming conflicts, and handle circular dependencies.
17 Jul 2026, 18:53 UTC

The Problem: Symbols the Compiler Cannot Find
When OCaml reports an Unbound module or Unbound value error, it means the compiler has reached a point in the source code where it expects a definition to exist, but the symbol is missing from the current scope or the linked libraries. In projects managed by Dune, this is rarely a syntax error and usually a configuration or naming mismatch.
Diagnostic Matrix
| Error Message | Likely Cause | Primary Check |
|---|---|---|
Unbound module X |
Missing library dependency or naming case error | Check dune file libraries stanza |
Unbound value X |
Missing open statement or incorrect qualification |
Check if Module.X is used instead of X |
Unbound module X (Internal) |
Circular dependency between modules | Check for mutual recursion across files |
Step 1: Verify Module Naming and Case
OCaml strictly enforces case sensitivity for identifiers. Modules must start with an uppercase letter. If you define a module as module my_utils = ..., the compiler treats my_utils as a value, not a module.
- Check: Ensure the module definition starts with an uppercase letter (e.g.,
module MyUtils = ...). - Check: Ensure the call site matches the case exactly.
Myutils.func ()will fail if the module is defined asMyUtils.
Step 2: Audit the Dune Configuration
Dune isolates libraries to prevent accidental dependencies. If you are using a function from a separate library within the same project, that library must be explicitly listed in the dune file of the current stanza.
Example Configuration:
Assume you have a library in lib/utils/dune and you are trying to use it in bin/main.ml.
# bin/dune
(executable
(name main)
(libraries utils)) # Ensure 'utils' is listed here
Risk: Adding every available library to every stanza increases binary size and slows down incremental compilation. Only add the specific libraries required for that module.
Step 3: Resolve Value Scope and Qualification
An Unbound value error often occurs when a module is correctly linked, but the function inside it isn't in the current namespace.
If you have module Utils with a function calculate, calling calculate () will fail unless you have performed one of the following:
- Qualified Access: Use
Utils.calculate (). This is the preferred method for large projects to avoid namespace pollution. - Open Statement: Add
open Utilsat the top of the file. - Local Open: Use
let open Utils in calculate ()for scoped access.
Step 4: Detect Circular Dependencies
If two modules, A.ml and B.ml, both require definitions from each other, the compiler may report an unbound value because it cannot determine which module to compile first.
Diagnostic: If the error appears only during the linking phase or intermittently during a clean build, check for mutual dependencies.
Fix: Extract the shared logic into a third module, C.ml, which both A and B depend on.
Verification and Testing
To verify the fix without running the entire test suite, use the following methods:
- Build Check: Run
dune buildfrom the project root. If the error is resolved, the build will complete or move to the next error. - Interactive Check: Run
dune utop. Inside the REPL, try to access the module:# let () = MyModule.some_func ();;. If the module is unbound here, thedunefile is missing the dependency. - Artifact Inspection: Check the
_builddirectory for the corresponding.cmi(compiled module interface) file. If the.cmiexists but the error persists, the issue is likely a missingopenor a case-sensitivity error.
Rollback and Recovery
Because these changes only affect configuration files and source code, rollback involves reverting the dune file or the module name change via version control (e.g., git checkout dune). Do not manually delete files in the _build directory; instead, use dune clean if you suspect a corrupted build cache.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.