jackc/pgx · error
multirange element OID not registered
Error message
multirange element OID not registered
What it means
Returned by Conn.LoadType for a typtype='m' (multirange) type when its range element OID is not in the connection's TypeMap (conn.go:1357-1359). A multirange codec wraps the same element type as its underlying range; if that element is unregistered the multirange cannot be built.
Source
Thrown at conn.go:1359
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
elementOID, err := c.getMultiRangeElementOID(ctx, oid)
if err != nil {
return nil, err
}
dt, ok := c.TypeMap().TypeForOID(elementOID)
if !ok {
return nil, errors.New("multirange element OID not registered")
}
return &pgtype.Type{Name: typeName, OID: oid, Codec: &pgtype.MultirangeCodec{ElementType: dt}}, nil
default:
return &pgtype.Type{}, errors.New("unknown typtype")
}
}
func (c *Conn) getArrayElementOID(ctx context.Context, oid uint32) (uint32, error) {
var typelem uint32
err := c.QueryRow(ctx, "select typelem from pg_type where oid=$1", oid).Scan(&typelem)
if err != nil {
return 0, err
}
return typelem, nil
}View on GitHub (pinned to ec1a0befd2)
Solutions
- LoadType and register the element type first, then the range, then the multirange.
- Use pg_range to find rngsubtype and ensure that OID is registered before calling LoadType on the multirange.
- Register a custom element codec via RegisterType if needed.
- Drive LoadType from a topologically-sorted dependency list.
Example fix
// before
mrt, err := conn.LoadType(ctx, "mymultirange") // element 'mytype' unknown
// -> "multirange element OID not registered"
// after
elem, err := conn.LoadType(ctx, "mytype")
if err != nil { return err }
conn.TypeMap().RegisterType(elem)
mrt, err := conn.LoadType(ctx, "mymultirange") Defensive patterns
Strategy: validation
Validate before calling
// multirange element == underlying range element; ensure registered
var elemOID uint32
conn.QueryRow(ctx, "select rngsubtype from pg_range r join pg_type t on t.oid=r.rngtypid where t.typname=$1", multirangeName).Scan(&elemOID)
if _, ok := conn.TypeMap().TypeForOID(elemOID); !ok {
// LoadType element, register, then LoadType multirange
} Type guard
func multirangeElementRegistered(m *pgtype.Map, elemOID uint32) bool { _, ok := m.TypeForOID(elemOID); return ok } Try / catch
if t, err := conn.LoadType(ctx, mrName); err != nil {
if strings.Contains(err.Error(), "multirange element OID not registered") {
// load+register element (and range), retry
}
return nil, err
} Prevention
- Register element, then range, then multirange — in that order.
- Resolve rngsubtype from pg_range before loading containers.
- Maintain a dependency graph for custom types.
When it happens
Trigger: Calling Conn.LoadType on a custom multirange (discontiguous of a custom range) before the range's element type has been loaded and registered.
Common situations: Custom multiranges over custom ranges over custom subtypes; loading multirange before range before element; schema migrations that introduce multiranges last but register them first in code.
Related errors
- array element OID not registered
- domain base type OID not registered
- range element OID not registered
- unknown typtype
AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04).
Data as JSON: /data/errors/0a4e0f4da8bf16c3.json.
Report an issue: GitHub.