laurent22/joplin · warning · Error
Synchronisation is already in progress.
Error message
Synchronisation is already in progress.
What it means
Thrown by `sync` when `Command.isLocked(lockFilePath)` returns true, signalling another process already holds the per-profile sync lock (a proper-lockfile lock on `${tmpdir}/synclock_<md5(profileDir)>`). The intent is to prevent two concurrent synchronizers from corrupting the same database. Note: this manually-thrown Error has no `.code`, so the surrounding catch (which only special-cases ELOCKED) re-throws it to the caller rather than printing the friendlier lock-held message.
Source
Thrown at packages/app-cli/app/command-sync.ts:147
}
}
public doingAuth() {
return !!this.oneDriveApiUtils_;
}
public async action(args: { options: { useLock?: number; target?: number; upgrade?: boolean } }) {
this.releaseLockFn_ = null;
// Lock is unique per profile/database
const lockFilePath = `${require('os').tmpdir()}/synclock_${md5(escape(Setting.value('profileDir')))}`; // https://github.com/pvorb/node-md5/issues/41
if (!(await pathExists(lockFilePath))) await writeFile(lockFilePath, 'synclock');
const useLock = args.options.useLock !== 0;
if (useLock) {
try {
if (await Command.isLocked(lockFilePath)) throw new Error(_('Synchronisation is already in progress.'));
this.releaseLockFn_ = await Command.lockFile(lockFilePath);
} catch (error) {
if (error.code === 'ELOCKED') {
const msg = _('Lock file is already being hold. If you know that no synchronisation is taking place, you may delete the lock file at "%s" and resume the operation.', error.file);
this.stdout(msg);
return;
}
throw error;
}
}
const cleanUp = () => {
cliUtils.redrawDone();
if (this.releaseLockFn_) {
this.releaseLockFn_();
this.releaseLockFn_ = null;
}View on GitHub (pinned to 2654b33620)
Solutions
- Wait for the in-progress sync to finish, then retry — concurrency is the intended block.
- If you are certain no sync is running, remove the stale lock file at the path printed in the ELOCKED message (or `${tmpdir}/synclock_<md5(profileDir)>`) and retry.
- Run different profiles from different processes instead of sharing one profile across concurrent invocations.
- As a last resort pass `--use-lock 0` to disable local locking (only when you can guarantee single-writer access).
Example fix
// before
if (await Command.isLocked(lockFilePath)) throw new Error(_('Synchronisation is already in progress.'));
// after - attach a stable code so callers/the catch can branch on it
if (await Command.isLocked(lockFilePath)) {
const e = new Error(_('Synchronisation is already in progress.'));
(e as any).code = 'SYNC_IN_PROGRESS';
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// Check the lock before attempting sync.
const lockFilePath = `${require('os').tmpdir()}/synclock_${md5(escape(Setting.value('profileDir')))}`;
if (await locker.check(lockFilePath)) {
throw new Error('Sync already in progress on this profile; wait or remove the stale lock.');
} Type guard
null
Try / catch
try {
await sync();
} catch (e) {
if (/Synchronisation is already in progress/.test(e.message)) {
// transient — wait for the other sync then retry once
await new Promise(r => setTimeout(r, 5000));
await sync();
} else throw e;
} Prevention
- Never run two sync writers against one profile concurrently.
- If a prior sync crashed, remove the stale lock file before retrying.
- Use separate profiles for parallel automation instead of sharing one.
When it happens
Trigger: Running `:sync` (or auto-sync) while another Joplin process or another `:sync` invocation for the same profile is already mid-sync. Also after a crashed prior sync that left a stale lock file within the 5-minute `stale` window, though proper-lockfile normally releases on process exit.
Common situations: Two terminals running `:sync` against one profile; the desktop app and CLI sharing a profile; a previous sync crashed and the OS has not reaped the lock; CI invoking sync in parallel jobs on one profile dir.
Related errors
- Please specify the sync target path.
- Cannot initialise synchroniser.
- lockError
- No item with ID ${itemId}
- More than one item match "%s". Please narrow down your query
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/3bfe7aa82e5e491d.
Report an issue: GitHub.