Skip to content

Refreshable tables with a TTL watermark panic in the frontend or the compute node #27509

Open

Description

@yuhao-su

Problem

Creating a refreshable table (refresh_mode = 'FULL_RELOAD') with WATERMARK ... WITH TTL panics. What panics depends on whether the TTL column is in the primary key.

TTL column not in the primary key: the frontend panics. StreamMaterialize::derive_staging_table_catalog maps the stream key to the pk-only staging table with mapping.try_map_all(stream_key).unwrap(). The stream key of a TTL table includes the TTL column, which the staging table does not have.

Reproduced on main (a73da86):

CREATE TABLE refresh_ttl (id INT PRIMARY KEY, ts TIMESTAMP, WATERMARK FOR ts AS ts - INTERVAL '1' HOUR WITH TTL) WITH (
    connector = '__for_testing_only_batch_posix_fs',
    batch_posix_fs.root = '/tmp/refresh_root',
    refresh_mode = 'FULL_RELOAD',
    match_pattern = '*.csv'
) FORMAT PLAIN ENCODE CSV (without_header = 'true', delimiter = ',');
ERROR:  Panicked when handling the request: called `Option::unwrap()` on a `None` value

The frontend log shows panicked at src/frontend/src/optimizer/plan_node/stream_materialize.rs:506:57.

TTL column in the primary key: the compute node panics. The staging catalog copies the main table's clean_watermark_indices without mapping them to its pk-only columns, so the index can be out of bounds.

CREATE TABLE refresh_ttl_pk (id INT, v INT, ts TIMESTAMP, PRIMARY KEY (id, ts), WATERMARK FOR ts AS ts - INTERVAL '1' HOUR WITH TTL) WITH (
    -- the same options as above
) FORMAT PLAIN ENCODE CSV (without_header = 'true', delimiter = ',');
ERROR:  Failed to run the query

Caused by these errors (recent errors listed first):
  1: gRPC request to meta service (call `/ddl_service.DdlService/CreateTable`) failed: Internal error
  2: completion notifier dropped

The compute node log shows panicked at src/stream/src/common/table/state_table.rs:1019:40: index out of bounds: the len is 2 but the index is 2. The index is that of ts in the table; the staging table only has the two pk columns.

Notes

Read from the code, not verified: supporting this combination would also require two changes in the MaterializeExecutor's MergingData stage:

  • feed TTL watermarks into the table before forwarding them (now it only forwards them);
  • skip expired rows during the merge instead of emitting deletes for them.

Until then, the frontend could reject the combination with a clear error instead of panicking.

Activity

  1. added this to the release-3.1 milestone on Oct 14, 2026
  2. yashaggarwal85d commented on Oct 23, 2026

    @yashaggarwal85d
    Contributor

    Hi @yuhao-su, I'd like to take this one. I'll go with the interim fix you suggested: reject refresh_mode = 'FULL_RELOAD' combined with WATERMARK ... WITH TTL in the frontend with a clear "not supported" error (covering both the TTL-column-in-pk and not-in-pk cases), plus planner and SLT tests. Proper TTL support in the refresh merge path can be a follow-up.

  3. added a commit that references this issue on Oct 23, 2026
    298067b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/bugType: Bug. Only for issues.

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions