mops check
Check Motoko canisters or files for syntax errors and type issues
mops check [args...]
Runs the Motoko compiler in check-only mode (moc --check). All package sources from the project are automatically included.
Arguments can be canister names (as defined in [canisters]) or file paths. When no arguments are given, checks all canisters defined in the [canisters] section of mops.toml.
When checking canisters, per-canister [canisters.<name>].args from mops.toml are applied alongside global [moc].args.
Exits with a non-zero code if any file has errors, making it suitable for CI pipelines. Warnings do not cause a failure by default.
Examples
Check all canisters defined in mops.toml
mops check
Check a specific canister
mops check backend
Check a single file
mops check src/main.mo
Check multiple files
mops check src/main.mo src/types.mo
Check with verbose output (shows the compiler command being run)
mops check --verbose
Treat warnings as errors
mops check -- -Werror
Arguments
[args...]
Canister names or file paths to check.
- Canister names — resolved from
[canisters.<name>]inmops.toml. Per-canisterargsare applied. - File paths —
.mofiles to check directly. Only global[moc].argsand CLI-- flagsare applied. - No arguments — checks all canisters defined in
mops.toml.
You cannot mix canister names and file paths in the same invocation.
On moc 2.0.0+, all file paths are checked in a single moc run. Each file still sees only its own imports, but a library several of them import is checked once and its diagnostics are reported once, and an error in one file does not hide the diagnostics of the others. Older moc versions concatenate several files into one program, so there each file gets its own run.
Options
--fix
Automatically apply fixes for supported diagnostics, including transitively imported files. Fixed files and the applied fix codes are printed to the console.
mops check --fix
After applying fixes, --fix re-checks all files and runs stable compatibility checks (if configured). If type-checking fails after fixing, stable checks are skipped.
Read-only files (e.g. frozen migration chain files chmod'd read-only) are skipped with a warning rather than aborting the run; the remaining files are still fixed.
Concurrent --fix runs in the same project (e.g. two agents on the same checkout) serialize via an advisory lock at .mops/fix.lock. The second invocation prints Waiting for another mops --fix run to finish... and resumes once the first one releases. Plain mops check is read-only and never blocks.
--verbose
Print the full moc invocation before running it.
--no-lint
Skip the automatic lint step for a single run, even when lintoko is pinned in [toolchain]. See Lint integration.
mops check --no-lint
--no-check-limit
Use the full migration chain, ignoring [canisters.<name>.migrations].check-limit. Useful with --fix to autofix issues in older migrations that the limit would normally skip. Also suppresses the pending-migration warning that runs when check-limit is set. See chain trimming.
mops check --fix --no-check-limit
--locked
Require an up-to-date mops.lock and never write it — fails if the lockfile is missing or no longer matches mops.toml and the registry. Intended for CI, so that a job can run this command without a preceding mops install. See mops install --locked.
Passing flags to the Motoko compiler
Any arguments after -- are forwarded directly to moc. For example, to treat all warnings as errors:
mops check -- -Werror
Global moc flags can be configured in mops.toml under [moc].args so they don't need to be passed on every invocation. See mops.toml reference.
Stable compatibility checking
When a canister has a [canisters.<name>.check-stable] section in mops.toml, mops check automatically runs a stable compatibility check after type-checking. This compares the deployed version against the current canister entrypoint to catch breaking changes to stable variables before deployment.
[canisters.backend]
main = "src/main.mo"
[canisters.backend.check-stable]
path = ".old/src/main.most"
If the file at path doesn't exist, the check fails with an error. For initial deployments with no prior version, commit a .most file at path with an empty actor so the check runs against an empty baseline:
// Version: 1.0.0
actor { };
On moc 1.15.0+, canisters with [migrations] configured and a .most baseline get better upgrade diagnostics, see diagnostics on moc 1.15.0+.
For more details, see mops check-stable.
When [canisters.<name>.migrations].check-limit is set, the stable check compares the deployed .most baseline against the local chain after compatibility checking. If more migrations are pending than check-limit allows, mops reports a diagnostic naming the latest pending file to fold into. If compat already failed, this replaces the misleading moc error; if compat passed anyway, it is shown as a warning. See chain trimming.
Enhanced migration support
When a canister has a [canisters.<name>.migrations] section in mops.toml, mops check automatically injects the --enhanced-migration flag for the canister.
If a stable compatibility check fails and [migrations] is configured, a hint is shown suggesting to create a new migration.
Lint integration
After type-checking succeeds, mops check automatically runs mops lint when lintoko is pinned in [toolchain].
This means mops check is the single command for all correctness checks — type errors and lint violations are both caught in one pass. Pass --no-lint to skip the lint step for a single run. Projects without a lintoko pin are unaffected.
mops check --fix
--fix is forwarded to both the Motoko compiler and lintoko, so both type-level and lint fixes are applied in a single invocation.
When file paths are passed explicitly (e.g. mops check src/Main.mo), linting is scoped to those files. When checking canisters (by name or with no arguments), linting covers all .mo files mops lint selects, which leaves out those the project's .gitignore excludes.
mops check only type-checks files — it does not produce any compiled output. To compile canisters, use mops build.