FlowiseAI/Flowise · error · Error

Error saving checkpoint

Error message

Error saving checkpoint

What it means

Thrown by PostgresSaver.put() when the INSERT ... ON CONFLICT upsert into the checkpoints table fails. The original error is console.error-logged and re-thrown generically. dataSource.destroy() always runs in finally after the queryRunner is released.

Source

Thrown at packages/components/nodes/memory/AgentMemory/PostgresAgentMemory/pgSaver.ts:229

            const row = [
                config.configurable?.thread_id || this.threadId,
                checkpoint.id,
                config.configurable?.checkpoint_id,
                Buffer.from(this.serde.stringify(checkpoint)), // Encode to binary
                Buffer.from(this.serde.stringify(metadata)) // Encode to binary
            ]
            const tableName = this.sanitizeTableName(this.tableName)

            const query = `INSERT INTO ${tableName} (thread_id, checkpoint_id, parent_id, checkpoint, metadata)
                           VALUES ($1, $2, $3, $4, $5)
                           ON CONFLICT (thread_id, checkpoint_id)
                           DO UPDATE SET checkpoint = EXCLUDED.checkpoint, metadata = EXCLUDED.metadata`

            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

  1. Read the console.error to get the underlying Postgres SQLSTATE (e.g. 42804 wrong datatype, 23505/unique violation handled by ON CONFLICT so unlikely, 57014 statement timeout) and act on it.
  2. Ensure the checkpoints table matches the DDL (checkpoint BYTEA, metadata BYTEA).
  3. Reduce checkpoint payload size or raise statement_timeout if you hit timeouts.
  4. Verify the role has INSERT and UPDATE privileges.
  5. 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 isPutSaveError(e: unknown): boolean {
  return e instanceof Error && e.message === 'Error saving checkpoint'
}

Try / catch

try {
  await saver.put(config, checkpoint, metadata)
} catch (e) {
  if (e instanceof Error && e.message === 'Error saving checkpoint') {
    // check log for SQLSTATE; verify BYTEA columns, payload size, role privileges
  }
  throw e
}

Prevention

When it happens

Trigger: Calling put(config, checkpoint, metadata) without a checkpoint_id returns {} early; otherwise the upsert runs and can fail on missing table, column mismatch, BYTEA encoding issues, oversized payload, or connection loss.

Common situations: Schema drift where checkpoint/metadata columns are not BYTEA. Very large checkpoints exceeding Postgres field size or statement_timeout. Connection drop. Permissions on INSERT/UPDATE.

Related errors


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