FlowiseAI/Flowise · error · Error

Time sync issue with database ${updatedAt} < ${timeAtLeast}

Error message

Time sync issue with database ${updatedAt} < ${timeAtLeast}

What it means

Postgres analog of error 263. Thrown in PostgresRecordManager.update when updateOptions.timeAtLeast is set and the database clock (this.getTime()) is older than that floor. Prevents writing backdated updated_at markers that would corrupt staleness-based cleanup.

Source

Thrown at packages/components/nodes/recordmanager/PostgresRecordManager/PostgresRecordManager.ts:313

            placeholders.push(`$${index * numOfColumns + i + 1}`)
        }
        return `(${placeholders.join(', ')})`
    }

    async update(keys: Array<{ uid: string; docId: string }> | string[], updateOptions?: UpdateOptions): Promise<void> {
        if (keys.length === 0) {
            return
        }

        const dataSource = await this.getDataSource()
        const queryRunner = dataSource.createQueryRunner()
        const tableName = this.sanitizeTableName(this.tableName)

        const updatedAt = await this.getTime()
        const { timeAtLeast, groupIds: _groupIds } = updateOptions ?? {}

        if (timeAtLeast && updatedAt < timeAtLeast) {
            throw new Error(`Time sync issue with database ${updatedAt} < ${timeAtLeast}`)
        }

        // Handle both new format (objects with uid and docId) and old format (strings)
        const isNewFormat = keys.length > 0 && typeof keys[0] === 'object' && 'uid' in keys[0]
        const keyStrings = isNewFormat ? (keys as Array<{ uid: string; docId: string }>).map((k) => k.uid) : (keys as string[])
        const docIds = isNewFormat ? (keys as Array<{ uid: string; docId: string }>).map((k) => k.docId) : keys.map(() => null)

        const groupIds = _groupIds ?? keyStrings.map(() => null)

        if (groupIds.length !== keyStrings.length) {
            throw new Error(`Number of keys (${keyStrings.length}) does not match number of group_ids ${groupIds.length})`)
        }

        const recordsToUpsert = keyStrings.map((key, i) => [key, this.namespace, updatedAt, groupIds[i], docIds[i]])

        const valuesPlaceholders = recordsToUpsert.map((_, j) => this.generatePlaceholderForRowAt(j, recordsToUpsert[0].length)).join(', ')

        const query = `INSERT INTO "${tableName}" (key, namespace, updated_at, group_id, doc_id) VALUES ${valuesPlaceholders} ON CONFLICT (key, namespace) DO UPDATE SET updated_at = EXCLUDED.updated_at, doc_id = EXCLUDED.doc_id;`

View on GitHub (pinned to abe4a8601a)

Solutions

  1. Run NTP/chrony on both hosts; verify with SELECT NOW() versus the app clock.
  2. Drop or relax timeAtLeast if your pipeline does not need the floor.
  3. Confirm this.getTime() reads from the DB (SELECT NOW()), not the app.
  4. Restart drifted DB instances or containers.

Example fix

// before
await mgr.update(keys, { timeAtLeast: Date.now() })
// after
await mgr.update(keys)
Defensive patterns

Strategy: retry

Validate before calling

const dbNow = await manager.getTime()
const skew = Math.abs(Date.now() - dbNow)
if (skew > 5_000) {
  throw new Error(`App/Postgres clock skew ${skew}ms; sync NTP.`)
}

Type guard

function isReasonableTimestamp(t: unknown, reference: number): t is number {
  return typeof t === 'number' && t <= reference + 60_000
}

Try / catch

try {
  await manager.update(keys, { timeAtLeast })
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Time sync issue')) {
    // verify SELECT NOW() vs app; resync; retry once
  }
  throw e
}

Prevention

When it happens

Trigger: Postgres server clock behind the application server; NTP drift on the DB host; caller passed a future-dated timeAtLeast; cross-region setup with unsynchronized clocks.

Common situations: Cloud Postgres (RDS/Aurora/CloudSQL) failing NTP after maintenance; Docker container clock drift; CI environments with skewed clocks.

Related errors


AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12). Data as JSON: /api/errors/31b3d94420c55abe. Report an issue: GitHub.