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

  1. Wait for the in-progress sync to finish, then retry — concurrency is the intended block.
  2. 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.
  3. Run different profiles from different processes instead of sharing one profile across concurrent invocations.
  4. 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

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


AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12). Data as JSON: /api/errors/3bfe7aa82e5e491d. Report an issue: GitHub.