laurent22/joplin · error · Error
Remote item %s has an updated_time in the future
Error message
Remote item %s has an updated_time in the future
What it means
A plain Error thrown inside the DELTA loop when a remote item's local copy has updated_time more than a full Day (24h) ahead of the current wall clock. The code comment is explicit: there is no automatic fix. The remote item on the sync target was manually edited (or corrupted) with a future timestamp far beyond now, so every sync loop re-detects the same conflict.
Source
Thrown at packages/lib/Synchronizer.ts:652
let local = locals[i];
const ItemClass = BaseItem.itemClass(local);
const path = BaseItem.systemPath(local);
// Safety check to avoid infinite loops.
// - In fact this error is possible if the item is marked for sync (via sync_time or force_sync) while synchronisation is in
// progress. When force_sync is not true, this is because the user is typing while the sync is running, so we should continue
// looping, as we don't want the sync to stop when there are still un-synced outgoing changes, otherwise this creates a race condition
// on mobile, where additional changes made during upload are not synced and don't trigger another sync, whereas a change made immediately
// after the sync has finished will trigger another sync. Once the user has stopped typing, it can then break out of the loop and continue
// the rest of the process.
// - It can also happen if the item is directly modified in the sync target, and set with an update_time in the future. In that case,
// the local sync_time will be updated to Date.now() but on the next loop it will see that the remote item still has a date ahead
// and will see a conflict. There's currently no automatic fix for this - the remote item on the sync target must be fixed manually
// (by setting an updated_time less than current time).
if (donePaths.indexOf(path) >= 0) {
const syncItem = await BaseItem.syncItem(syncTargetId, local.id, { fields: ['force_sync'] });
if (local.updated_time > time.unixMs() + Day) {
throw new Error(sprintf('Remote item %s has an updated_time in the future', path));
} else if (local.updated_time > time.unixMs()) {
throw new JoplinError(sprintf('Processing a path that has already been done: %s. Remote item has an updated_time in the future', path), 'processingPathTwice');
} else if (syncItem.force_sync) {
throw new JoplinError(sprintf('Processing a path that has already been done: %s. Item was marked for sync using force_sync', path), 'processingPathTwice');
} else {
throw new JoplinError(sprintf('Processing a path that has already been done: %s. The user is making changes while the sync is in progress', path), 'changedDuringSync');
}
}
const remote: RemoteItem = result.neverSyncedItemIds.includes(local.id) ? null : await this.apiCall('stat', path);
let action: SyncAction = null;
let itemIsReadOnly = false;
let reason = '';
let remoteContent = null;
const getConflictType = (conflictedItem: { type_?: number }) => {
if (conflictedItem.type_ === BaseModel.TYPE_NOTE) return SyncAction.NoteConflict;
if (conflictedItem.type_ === BaseModel.TYPE_RESOURCE) return SyncAction.ResourceConflict;View on GitHub (pinned to 2654b33620)
Solutions
- Manually fix the remote item on the sync target so its updated_time is less than the current time (as the code comment instructs).
- If the remote target is a filesystem/WebDAV, edit the JSON body of the item and set updated_time to a past value.
- Correct the system clock on the device that produced the bad timestamp to prevent recurrence.
- As a last resort, delete the offending remote item and let Joplin recreate it from the local copy.
Defensive patterns
Strategy: validation
Validate before calling
// Before syncing, detect items with implausible future timestamps
const Day = 24 * 60 * 60 * 1000;
const now = Date.now();
const bad = items.filter(i => i.updated_time > now + Day);
if (bad.length) {
// flag for manual fix on the sync target before syncing
reportFutureTimestampItems(bad);
} Try / catch
try {
await synchronizer.start(options);
} catch (error) {
if (/updated_time in the future/.test(error.message)) {
// surface the path to the user for manual remote fix
showManualFixGuidance(error.message);
return;
}
throw error;
} Prevention
- Keep system clocks NTP-synced on all devices to avoid future-dated items.
- Avoid editing items directly on the sync target with hand-crafted timestamps.
- Monitor sync logs for recurring 'future' errors and fix the named remote items promptly.
When it happens
Trigger: Encountered when donePaths already contains the path (re-processing) AND local.updated_time exceeds time.unixMs() + Day. This happens after a previous sync pulled down a remote item whose updated_time was set more than 24h in the future — e.g. someone edited the .md file directly on the WebDAV/Joplin Server target and wrote a wrong timestamp.
Common situations: Manual editing of items directly on the sync target (filesystem, WebDAV, S3) with clock skew or hand-edited metadata; a device with a badly wrong system clock previously synced the item.
Related errors
- processingPathTwice
- rejectedByTarget
- Could not get lastModified date for resource: ${JSON.stringi
- Invalid date: ${lastModifiedString}
- Timed out trying to get sync target clock time
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/db4e6189161fd92e.
Report an issue: GitHub.