Skip to content

Commit 6a19c6b

Browse files
Kamiruscursoragent
andauthored
fix(cli): prevent check --fix crash when moc produces no output (#570)
## What changes for users `mops check --fix` no longer crashes when `moc` produces no output. Previously the autofix pass aborted the entire command with an unhandled exception: ``` TypeError: Cannot read properties of undefined (reading 'split') at parseDiagnostics (.../dist/helpers/autofix-motoko.js) ``` This was blocking deployments in memory-constrained environments (CI/containers) where `moc` can fail to spawn or get OOM-killed — `execa(..., { reject: false })` then resolves with `stdout === undefined`. Even unrelated frontend-only changes couldn't ship because the backend `check --fix` step crashed. ## Why `parseDiagnostics(stdout: string)` assumed `moc` always returns captured stdout. With `reject: false`, a failed/killed `moc` yields `undefined`, and `.split()` threw. Reported by multiple users in production. **Before:** any `moc` spawn/kill failure during `--fix` → hard crash, command aborts. **After:** missing output is treated as "no fixes to apply"; the subsequent regular check reports the real failure (e.g. non-zero exit) with a clear message. ## Notes Targeted unit test added for the `undefined` / empty stdout paths. Made with [Cursor](https://cursor.com) Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 851929f commit 6a19c6b

3 files changed

Lines changed: 13 additions & 1 deletion

File tree

cli/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Mops CLI Changelog
22

33
## Next
4+
- Fix `mops check --fix` crashing with `TypeError: Cannot read properties of undefined (reading 'split')` when `moc` produces no output (e.g. it fails to spawn or is killed by the OOM killer in a memory-constrained container). The autofix pass now treats missing `moc` output as "no fixes to apply" and lets the regular check report the real failure, instead of aborting the whole command with an unhandled exception.
5+
46
- Fix `mops check --fix` and `mops lint --fix` corrupting source files when two `mops` processes run concurrently in the same project (e.g. two coding agents on the same checkout). Concurrent runs could apply stale `moc` byte offsets to a sibling's already-mutated file, leaving source like `let nat = identity` (with the type-arg and call dropped) or `list.sortInPlace(` with an unclosed paren. `--fix` invocations now acquire a project-root advisory lock at `.mops/fix.lock` and serialize, cargo-style ("Waiting for another `mops --fix` run to finish..."). Read-only `mops check` and `mops lint` are unchanged.
57

68
- Deprecate the `dfx` replica in `mops bench`, `mops test --mode replica`, and `mops watch`. Behavior is unchanged — `--replica dfx`, the implicit `dfx` fallback when no `[toolchain.pocket-ic]` is set, and the dfx-bundled PocketIC fallback all still work — but each now prints a warning. Run `mops toolchain use pocket-ic <version>` to silence it. The `dfx` paths will be removed and the default flipped to PocketIC in mops v3 — `dfx` is being deprecated upstream and PocketIC is a better fit for benchmarks and replica tests (deterministic, in-process, no background daemon).

cli/helpers/autofix-motoko.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ export interface MocDiagnostic {
2626
notes: string[];
2727
}
2828

29-
export function parseDiagnostics(stdout: string): MocDiagnostic[] {
29+
export function parseDiagnostics(stdout: string | undefined): MocDiagnostic[] {
30+
if (!stdout) {
31+
return [];
32+
}
3033
return stdout
3134
.split("\n")
3235
.filter((l) => l.trim())

cli/tests/check-fix.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ describe("check --fix", () => {
6262
return runFilePath;
6363
}
6464

65+
test("parseDiagnostics tolerates missing moc output", () => {
66+
// execa with reject:false yields undefined stdout when moc fails to spawn
67+
// or is killed (e.g. OOM); parsing must degrade to no diagnostics, not throw.
68+
expect(parseDiagnostics(undefined)).toEqual([]);
69+
expect(parseDiagnostics("")).toEqual([]);
70+
});
71+
6572
test("M0223", async () => {
6673
await testCheckFix("M0223.mo", { M0223: 1 });
6774
});

0 commit comments

Comments
 (0)