jackc/pgx · error

domain base type OID not registered

Error message

domain base type OID not registered

What it means

Returned by Conn.LoadType for a typtype='d' (domain) type when its base type OID (pg_type.typbasetype) is not found in the connection's TypeMap (conn.go:1331-1333). A domain is just a named constraint over a base type, so pgx reuses the base type's Codec; without the base registered it cannot construct the domain codec.

Source

Thrown at conn.go:1333

		}

		dt, ok := c.TypeMap().TypeForOID(elementOID)
		if !ok {
			return nil, errors.New("array element OID not registered")
		}

		return &pgtype.Type{Name: typeName, OID: oid, Codec: &pgtype.ArrayCodec{ElementType: dt}}, nil
	case "c": // composite
		fields, err := c.getCompositeFields(ctx, oid)
		if err != nil {
			return nil, err
		}

		return &pgtype.Type{Name: typeName, OID: oid, Codec: &pgtype.CompositeCodec{Fields: fields}}, nil
	case "d": // domain
		dt, ok := c.TypeMap().TypeForOID(typbasetype)
		if !ok {
			return nil, errors.New("domain base type OID not registered")
		}

		return &pgtype.Type{Name: typeName, OID: oid, Codec: dt.Codec}, nil
	case "e": // enum
		return &pgtype.Type{Name: typeName, OID: oid, Codec: &pgtype.EnumCodec{}}, nil
	case "r": // range
		elementOID, err := c.getRangeElementOID(ctx, oid)
		if err != nil {
			return nil, err
		}

		dt, ok := c.TypeMap().TypeForOID(elementOID)
		if !ok {
			return nil, errors.New("range element OID not registered")
		}

		return &pgtype.Type{Name: typeName, OID: oid, Codec: &pgtype.RangeCodec{ElementType: dt}}, nil
	case "m": // multirange

View on GitHub (pinned to ec1a0befd2)

Solutions

  1. LoadType the base type first and register it, then LoadType the domain.
  2. Walk pg_type.typbasetype chains in dependency order before loading domains.
  3. If the base is built-in, ensure your TypeMap has the default codecs loaded (it does by default).
  4. Register the base codec manually via RegisterType if you provide a custom implementation.

Example fix

// before
dt, err := conn.LoadType(ctx, "pos_int") // domain over custom base 'my_int'
// -> "domain base type OID not registered"

// after
base, err := conn.LoadType(ctx, "my_int")
if err != nil { return err }
conn.TypeMap().RegisterType(base)
dt, err := conn.LoadType(ctx, "pos_int")
Defensive patterns

Strategy: validation

Validate before calling

// resolve typbasetype and ensure it is registered first
var baseOID uint32
conn.QueryRow(ctx, "select typbasetype from pg_type where typname=$1", domainName).Scan(&baseOID)
if _, ok := conn.TypeMap().TypeForOID(baseOID); !ok {
    // LoadType the base, register, then LoadType the domain
}

Type guard

func baseRegistered(m *pgtype.Map, baseOID uint32) bool { _, ok := m.TypeForOID(baseOID); return ok }

Try / catch

if t, err := conn.LoadType(ctx, domainName); err != nil {
    if strings.Contains(err.Error(), "domain base type OID not registered") {
        // load+register base, retry
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling Conn.LoadType on a domain whose underlying base type is custom and unregistered — e.g. CREATE DOMAIN positive_int AS my_int where my_int is a custom type that has not been loaded yet.

Common situations: Loading a domain defined over a custom base type without first registering the base; schema changes that introduce a domain over a new base type; migrations that create domains before their base types are mapped.

Related errors


AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04). Data as JSON: /data/errors/867f3d854071a371.json. Report an issue: GitHub.