windmill-labs/windmill · error · MalformedLockfileError
wmill-lock.yaml is malformed (expected an object). Refusing
Error message
wmill-lock.yaml is malformed (expected an object). Refusing to operate to avoid corrupting the lockfile.
What it means
The wmill CLI stores dependency and sync state in wmill-lock.yaml. Before any operation it parses this file; if the parsed YAML is not a non-null object, the CLI throws MalformedLockfileError and refuses to proceed, because writing to a malformed lockfile would destroy user data. This guards against hand-edited or corrupted lockfiles.
Source
Thrown at cli/src/utils/metadata.ts:1252
yamlStringify(inMemoryLock as Record<string, any>, yamlOptions),
"utf-8",
);
inMemoryLock = null;
}
export async function readLockfile(): Promise<Lock> {
if (inMemoryLock) return inMemoryLock;
let parsed: unknown;
try {
parsed = await yamlParseFile(WMILL_LOCKFILE);
} catch {
const lock: Lock = { locks: {}, version: CURRENT_LOCK_VERSION };
await writeFile(WMILL_LOCKFILE, yamlStringify(lock, yamlOptions), "utf-8");
log.info(colors.green("wmill-lock.yaml created"));
return lock;
}
if (typeof parsed != "object" || parsed == null) {
throw new MalformedLockfileError(
"wmill-lock.yaml is malformed (expected an object). " +
"Refusing to operate to avoid corrupting the lockfile.",
);
}
const conf = parsed as Lock;
if (conf.version != null && !KNOWN_LOCK_VERSIONS.includes(conf.version)) {
throw new UnknownLockVersionError(
`wmill-lock.yaml is at unknown version "${conf.version}". This was ` +
`written by a newer wmill CLI; please upgrade with \`wmill upgrade\`. ` +
`Refusing to operate to avoid corrupting the lockfile.`,
);
}
return conf;
}
function v2LockPath(path: string, subpath?: string) {
const normalizedPath = normalizeLockPath(path);
if (subpath) {View on GitHub (pinned to e474e8803c)
Solutions
- Open wmill-lock.yaml and ensure the top level is a YAML mapping with keys like 'locks' and 'version'
- If the file is corrupted or unimportant, delete it and regenerate it with the wmill CLI (e.g. re-run the sync/pull command that recreates the lockfile)
- Restore a previous version from git (git checkout -- wmill-lock.yaml) or from a backup
- Fix YAML syntax errors such as stray characters, tabs, or unquoted values that cause the document to parse as a scalar
Example fix
# before (malformed)
wmill-lock.yaml:
- just a list
# after (valid)
version: 1
locks: {} Defensive patterns
Strategy: validation
Validate before calling
import { parse } from "yaml";
const parsed = parse(await readFile("wmill-lock.yaml", "utf-8"));
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
throw new Error("wmill-lock.yaml is not an object — restore it from git or delete and regenerate it before running wmill.");
} Type guard
function isLockObject(v: unknown): v is Record<string, unknown> {
return typeof v === "object" && v !== null && !Array.isArray(v);
} Try / catch
try {
await wmillSyncPull();
} catch (e) {
if (e instanceof MalformedLockfileError) {
// restore from git or delete + regenerate the lockfile
} else throw e;
} Prevention
- Don't hand-edit wmill-lock.yaml; let the CLI manage it
- Commit the lockfile so a corrupted copy can be restored with git checkout
- Add the lockfile to code-review checks so PRs with scalar/empty roots are caught
- Never commit an empty or placeholder wmill-lock.yaml
When it happens
Trigger: Running any wmill command that reads the lockfile (sync, push, pull, deploy, etc.) when wmill-lock.yaml parses to a scalar, array, string, number, or is empty/null instead of a mapping object.
Common situations: Manually editing wmill-lock.yaml and accidentally replacing the top-level mapping with a scalar or list; truncating the file during a failed write or git merge conflict; a tool rewriting the file with the wrong root type; checking in an empty or placeholder lockfile.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Cannot regenerate lock for flow ${remote_path}: missing inli
- Failed to queue flow dependencies job: ${queueResponse.statu
- Failed to poll flow dependencies job ${jobId}: ${e?.message
- Failed to generate lockfile: ${message}
- Found ${wrongFormatPaths.length} directory(ies) using ${foun
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/4361ff16ffe2fdb2.
Report an issue: GitHub.