CockroachDB 25.1.2 fixes type resolution across multi-table replication
A helper could resolve one table's user-defined type successfully and leave invalid state for the next table. The March patch repairs multi-table LDR startup and several upgrade paths.
A helper can complete one operation successfully while returning state that makes the next operation fail. That is the mechanism behind CockroachDB 25.1.2's correction for multi-table logical data replication involving user-defined types. The first type resolution could succeed, but a later iteration received a nil map and panicked.
The March 12 release notes describe the visible consequence as failure to start affected multi-table LDR streams. The backported fix explains the state transfer between calls. This is a startup defect with a specific schema trigger, rather than a general claim that replication cannot process multiple tables.
I like CockroachDB's explicit consistency model and accept the coordination it requires. Replication between independent clusters adds another model on top of that. A startup failure needs to be understood at the level of the stream and its schema, without assuming that the database's local transaction guarantees describe every cross-cluster operation.
The failing combination includes multiple tables and user-defined types
The fix's explanation identifies a loop that resolves user-defined types. A successful call returned a nil map, which the loop passed into the next call. The next iteration then panicked. A test containing one table could miss this transition because it never exercises the subsequent use of returned state.
This is a useful failure mode to distinguish from rejecting an unsupported type. The published change describes a bug in the helper's state handling, not a deliberate incompatibility rule. The repair allows the affected multi-table startup path to proceed through type resolution.
The important invariant is across calls. A helper used in a loop must return state suitable for the next invocation, including on success. An error-only review would miss the invalid state because the operation that produced it had already reported success. The regression case needs to consume that returned state again, since testing the first result alone cannot exercise the failure described in the fix.
An enum is more than its displayed text
The ENUM reference documents a user-defined type as a named set of values. A table can refer to that type in a column definition, which adds a schema dependency beyond the primitive column layout.
A small example illustrates the shape that makes type resolution relevant. The SQL creates one type and two tables that use it:
CREATE TYPE record_state AS ENUM ('open', 'closed');
CREATE TABLE current_records (id INT PRIMARY KEY, state record_state);
CREATE TABLE archived_records (id INT PRIMARY KEY, state record_state);
This example is a schema illustration, not a complete LDR setup. Replicating such tables requires understanding the named type as well as the row values. Two columns displaying the same string are not sufficient evidence that their schema dependencies have been resolved correctly.
LDR does not create one serializable transaction across clusters
The LDR overview describes table replication between active source and destination clusters. Both can receive application traffic. The replicating tables reach eventual consistency, while each cluster separately retains CockroachDB's internal Raft-based consistency guarantees.
The overview describes last-write-wins conflict resolution using MVCC timestamps and a dead-letter queue for unresolved conflicts. These are explicit parts of the replication model. Fixing startup does not change those semantics or turn independent cluster transactions into one globally serializable history.
That distinction matters when interpreting the March release. A stream that can now start has crossed a setup boundary. Whether its conflict behavior matches an application's requirements remains a separate question, defined by the LDR model rather than by the absence of a startup panic.
Stream creation has source and destination schema context
The CREATE LOGICAL REPLICATION STREAM reference documents creation from the destination cluster, with fully qualified source and destination table names. Its multi-table form supplies lists of tables. The command also requires administrative or replication authority.
Those inputs explain why a real setup exercises more than connectivity. The database must establish the stream's table associations and resolve the relevant schema. The corrected loop sits within that preparation, before normal ongoing replication can demonstrate progress.
I find the multi-table condition more informative than a broad recommendation to exercise replication after upgrading. It identifies a concrete missing case in a single-table rehearsal. A representative setup must include the schema dependencies that change the startup path.
The patch also repairs upgrade progress
Version 25.1.2 separately fixes upgrade finalization that could become stuck while backfilling jobs under contention. The notes say the step now uses locks to ensure progress. They also correct a crash when an upgrade encounters a malformed job without payload information.
These fixes concern completing administrative state transitions, as does the LDR startup correction. In each case, a successful steady-state query would provide limited evidence about the failing path. The March release makes the affected setup and upgrade operations complete under their stated conditions, while leaving the documented cross-cluster replication semantics unchanged.