Skip to content

DESCRIBE lists the primary-key column twice with contradictory nullability on document_strict collections #173

Description

@mkhairi

Tested against: origin/main @ 8e84501a (post-v0.3.0 main head, 2026-07-07)

Severity: Medium — schema introspection returns a malformed column list;
any client that drives its column model from DESCRIBE sees a duplicate
primary-key column with conflicting null constraints.

Summary

DESCRIBE <collection> on a document_strict collection created with an
explicit id TEXT PRIMARY KEY now returns the id column twice
once as id TEXT / nullable=false and once as
id TEXT PRIMARY KEY / nullable=true — plus a new __storage metadata
row. The two id rows contradict each other on nullability, and the
PRIMARY-KEY-marked one claiming nullable=true is wrong on its own.

Regression relative to 67c4572d, where DESCRIBE listed each column
once. Notably, the direct pg_attribute read for the same collection
now dedupes the explicit id against the synthetic primary key correctly
on this build — DESCRIBE appears to have missed the same dedup and
regressed in the opposite direction.

Repro

CREATE COLLECTION desc_repro (id TEXT PRIMARY KEY, label TEXT) WITH (engine='document_strict');
DESCRIBE desc_repro;
--    field   |       type       | nullable
--  id        | TEXT             | false
--  id        | TEXT PRIMARY KEY | true      -- duplicate, contradictory nullability
--  label     | TEXT             | true
--  __storage | document_strict  | false     -- new internal row
-- (4 rows)                                  -- expected: id once, label once

Expected

  1. One row per user column; the explicit id and the synthetic primary
    key resolve to a single entry (same dedup the pg_attribute path
    already performs on this build).
  2. The primary-key column reports nullable=false.
  3. Internal metadata rows, if exposed at all, stay consistently
    __-prefixed (the __storage row follows that convention and is
    easy to filter; the duplicate id is the defect).

Files (best-guess)

  • nodedb/src/control/planner/catalog_adapter.rs — the recent
    explicit-id/synthetic-PK dedup landed here for catalog reads; DESCRIBE
    resolves through a different path.
  • nodedb/src/server/shared/ddl/neutral/collection/describe.rs
    DESCRIBE handler; likely concatenates the declared column list with
    the synthetic PK entry without deduping by field name.

Operational context

DESCRIBE is the introspection surface NodeDB itself recommends where
pg_catalog coverage is thin, so wire clients build their column models
from it. A duplicated PK column with conflicting null flags propagates
into client-side schema caches, dumps, and generated DDL — consumers
must now dedupe defensively and guess which nullability to trust.

Metadata

Metadata

Assignees

No one assigned

    Labels

    engine:documentDocument engine (schemaless + strict)regressionWorked on an earlier build; broke sincesev:3-mediumFeature wrong, but operational and a workaround existstype:bugA defect — broken, incorrect, or lost data

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions