Responses Store Schema Migration (v2 → v3)

Replace the disposable v3 response store with a fresh v4 database before starting current releases; startup creates the required schema.
On this page

Schema version 3 stores the responses store’s JSON payload columns as native binary columns instead of TEXT:

TableColumns changed to binary
responsesresponse_object, input, messages

Binary columns let the optional zstd compression store a raw zstd frame (and uncompressed rows store raw JSON bytes). The column type is BLOB on SQLite and BYTEA on PostgreSQL.

The proxy refuses to start against a database still stamped at version 2 — the store initialization fails with:

schema version mismatch in '<responses_table>_schema_version': stored
version 2, expected 3; database migration required

Migration is a one-time, operator-run step. It is not applied automatically on startup. Take a backup before running it.

Substitute your configured responses table name (openai_responses by default) for the <responses_table> placeholder below.

PostgreSQL

PostgreSQL is strictly typed, so the columns must be altered from TEXT to BYTEA. convert_to(col, 'UTF8') reinterprets the existing JSON text as its UTF-8 bytes. Run the following in one transaction:

BEGIN;

ALTER TABLE <responses_table>
    ALTER COLUMN response_object TYPE BYTEA USING convert_to(response_object, 'UTF8'),
    ALTER COLUMN input           TYPE BYTEA USING convert_to(input, 'UTF8'),
    ALTER COLUMN messages        TYPE BYTEA USING convert_to(messages, 'UTF8');

UPDATE <responses_table>_schema_version SET version = 3;

COMMIT;

SQLite

SQLite uses dynamic typing, so a value keeps the storage class it was written with regardless of the column’s declared affinity. CAST(col AS BLOB) rewrites each stored TEXT value to its BLOB storage class. Run the following in one transaction:

BEGIN;

UPDATE <responses_table>
SET response_object = CAST(response_object AS BLOB),
    input           = CAST(input AS BLOB),
    messages        = CAST(messages AS BLOB);

UPDATE <responses_table>_schema_version SET version = 3;

COMMIT;

The “openai_conversations” Filter

The openai_conversations filter does not store responses, but it shares the response-store schema and therefore generates an internal, always-empty <conversations_table>_unused_responses table (default openai_conversations_unused_responses) with its own <conversations_table>_unused_responses_schema_version. That version is gated by the same global schema version, so an existing conversations deployment stamped at version 2 also refuses to start until its generated table is stamped at version 3.

Because the generated table is never written, no data conversion is needed — only the schema version has to be bumped.

UPDATE openai_conversations_unused_responses_schema_version SET version = 3;

The conversations (<conversations_table>) and items tables are unchanged by this migration and must not be altered.