FlowiseAI/Flowise · error · Error
Error saving checkpoint
Error message
Error saving checkpoint
What it means
Thrown by SQLiteSaver.put() when the INSERT OR REPLACE upsert into the checkpoints table fails. Underlying error logged then re-thrown generically; finally destroys dataSource.
Source
Thrown at packages/components/nodes/memory/AgentMemory/SQLiteAgentMemory/sqliteSaver.ts:213
if (!config.configurable?.checkpoint_id) return {}
try {
const queryRunner = dataSource.createQueryRunner()
const row = [
config.configurable?.thread_id || this.threadId,
checkpoint.id,
config.configurable?.checkpoint_id,
this.serde.stringify(checkpoint),
this.serde.stringify(metadata)
]
const tableName = this.sanitizeTableName(this.tableName)
const query = `INSERT OR REPLACE INTO ${tableName} (thread_id, checkpoint_id, parent_id, checkpoint, metadata) VALUES (?, ?, ?, ?, ?)`
await queryRunner.manager.query(query, row)
await queryRunner.release()
} catch (error) {
console.error('Error saving checkpoint', error)
throw new Error('Error saving checkpoint')
} finally {
await dataSource.destroy()
}
return {
configurable: {
thread_id: config.configurable?.thread_id || this.threadId,
checkpoint_id: checkpoint.id
}
}
}
async delete(threadId: string): Promise<void> {
if (!threadId) {
return
}
const dataSource = await this.getDataSource()View on GitHub (pinned to abe4a8601a)
Solutions
- Check console.error for the real SQLite error (SQLITE_BUSY, SQLITE_READONLY, SQL logic error, etc.).
- Recreate the checkpoints table to match current DDL.
- Enable WAL mode and raise busy_timeout via additionalConfig to mitigate write contention.
- Ensure the DB file/dir is writable.
- Maintainer: rethrow with cause.
Example fix
// before
} catch (error) {
console.error('Error saving checkpoint', error)
throw new Error('Error saving checkpoint')
}
// after
} catch (error) {
throw new Error(`Error saving checkpoint: ${(error as Error).message}`, { cause: error })
} Defensive patterns
Strategy: try-catch
Validate before calling
function assertCheckpointWritable(checkpoint: { id?: unknown }, config: { configurable?: { checkpoint_id?: unknown } }) {
if (!config.configurable?.checkpoint_id) throw new Error('put() requires config.configurable.checkpoint_id')
if (typeof checkpoint.id !== 'string' || !checkpoint.id) throw new Error('checkpoint.id must be a non-empty string')
} Type guard
function isSqliteSaveError(e: unknown): boolean {
return e instanceof Error && e.message === 'Error saving checkpoint'
} Try / catch
try {
await sqliteSaver.put(config, checkpoint, metadata)
} catch (e) {
if (e instanceof Error && e.message === 'Error saving checkpoint') {
// inspect log for SQLITE_BUSY/READONLY; enable WAL; verify schema BLOB columns
}
throw e
} Prevention
- Enable WAL and set busy_timeout in additionalConfig for write-heavy workloads.
- Keep the SQLite file/dir writable by the Flowise process.
- Migrate the checkpoints schema after upgrades.
When it happens
Trigger: put() with checkpoint_id present while the table is missing, schema drifted (non-BLOB columns), payload too large, file locked, or role/FS permissions issue.
Common situations: Schema drift after upgrade. SQLite busy/locked under concurrent writes. Filesystem read-only. Very large serialized checkpoints.
Related errors
- Error saving checkpoint
- Error retrieving ${tableName}
- Error retrieving ${tableName}
- Error creating ${this.tableName} table
- Error listing ${tableName}
AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12).
Data as JSON: /api/errors/84a062506573ce5c.
Report an issue: GitHub.