Skip to content

Snapshot restore silently leaves the target schema incomplete: partitioned indexes never attached, extensions not restored #1093

Description

@siriusfreak

What happened

On a snapshot into an empty target, the schema restore logs restore: N errors ignored and continues — but two classes of those "ignored" errors leave the target's schema permanently incomplete, with no later signal that anything is missing.

Version: v1.3.1, postgres → postgres, source PG14, target PG16.

1. Partitioned indexes are never attached

ALTER INDEX ... ATTACH PARTITION is executed in the first restore pass, before the parent index exists, so it fails. The later restoring schema indices and constraints pass creates the parent index but does not retry the attach, so the parent index stays indisvalid = false forever.

Minimal reproduction:

-- source
CREATE TABLE jfbus_events (
  event_id bigint, topic_id int, partition_id int,
  PRIMARY KEY (event_id, topic_id, partition_id)
) PARTITION BY LIST (partition_id);
CREATE TABLE jfbus_events_0 PARTITION OF jfbus_events FOR VALUES IN (0);
CREATE TABLE jfbus_events_1 PARTITION OF jfbus_events FOR VALUES IN (1);
CREATE INDEX jfbus_events_topic_partition_event_id
  ON jfbus_events (topic_id, partition_id, event_id);
INSERT INTO jfbus_events SELECT g, 1, g % 2 FROM generate_series(1,5000) g;

Run a snapshot into an empty target with PGSTREAM_POSTGRES_SNAPSHOT_TABLES="public.*". The restore logs:

restore: 5 errors ignored
  relation does not exist: ERROR: relation "public.jfbus_events_pkey" does not exist:
    STATEMENT: ALTER INDEX public.jfbus_events_pkey ATTACH PARTITION public.jfbus_events_0_pkey;
  relation does not exist: ERROR: relation "public.jfbus_events_topic_partition_event_id" does not exist:
    STATEMENT: ALTER INDEX public.jfbus_events_topic_partition_event_id ATTACH PARTITION ...
restoring schema indices and constraints
logical replication started

All 5000 rows land, and then on the target:

SELECT indexrelid::regclass, indrelid::regclass FROM pg_index WHERE NOT indisvalid;

 jfbus_events_pkey                      | jfbus_events
 jfbus_events_topic_partition_event_id  | jfbus_events

A non-partitioned table in the same run is fine.

Why this matters beyond the index itself. An invalid partitioned index is not usable as a constraint, so the target ends up with no enforceable primary key for that table. Downstream that means no replica identity for UPDATE/DELETE, and no conflict target for on_conflict_action: update — so subsequent replication of that table silently drops rows (with strict_mode: false, the failed query is dropped and the checkpoint advanced).

Expected: either the attach is ordered after the parent index is created, or it is retried in the restoring schema indices and constraints pass.

2. Extensions are not restored

Same run, separate symptom. With pg_trgm installed on the source and an index that uses it:

-- source
CREATE EXTENSION pg_trgm;
CREATE INDEX trg_gin ON trg USING gin (lower(name) gin_trgm_ops);

the restore reports:

restore: 2 errors ignored
  relation does not exist: ERROR: operator class "public.gin_trgm_ops"
  does not exist for access method "gin":
    STATEMENT: CREATE INDEX trg_gin ON trg USING gin (lower(name) gin_trgm_ops);

and afterwards the target has SELECT extname FROM pg_extension → only plpgsql, with the index missing. The data loads fine, so the only trace is the ignored-error line.

Expected: either extensions are included in the restored schema, or their absence is reported as something stronger than an ignored error, since every dependent index is silently skipped.

Suggestion

Both are cases where restore: N errors ignored hides a target schema that does not match the source. Even without changing the ordering, a post-restore summary — "these objects were not created" — would turn a silent divergence into something an operator can act on.

Activity

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

    bugSomething isn't workingsnapshotSnapshot related work

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions