jackc/pgx · error

unknown typtype

Error message

unknown typtype

What it means

Returned by Conn.LoadType when pg_type.typtype of the requested type is not one of b/c/d/e/r/m (base/composite/domain/enum/range/multirange). The switch falls through to default at conn.go:1364. This usually means the type is a pseudo-type (typtype='p', e.g. void, anyelement, trigger, record), a table row type, or a typtype introduced by a newer PostgreSQL version pgx does not yet handle.

Source

Thrown at conn.go:1364

		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
}

func (c *Conn) getRangeElementOID(ctx context.Context, oid uint32) (uint32, error) {
	var typelem uint32

	err := c.QueryRow(ctx, "select rngsubtype from pg_range where rngtypid=$1", oid).Scan(&typelem)

View on GitHub (pinned to ec1a0befd2)

Solutions

  1. Do not call LoadType on pseudo-types or table row types; they are not derivable types pgx models.
  2. For a table-like payload, define a CREATE TYPE … AS (…) composite and LoadType that name.
  3. Upgrade pgx — newer versions may handle additional typtypes.
  4. Check SELECT typtype FROM pg_type WHERE typname=… to confirm the kind before calling LoadType.

Example fix

// before
t, err := conn.LoadType(ctx, "trigger") // typtype='p' -> unknown typtype

// after
var tt string
conn.QueryRow(ctx, "select typtype::text from pg_type where typname=$1", name).Scan(&tt)
if tt != "b" && tt != "c" && tt != "d" && tt != "e" && tt != "r" && tt != "m" {
    return nil, fmt.Errorf("type %s is %q, not LoadType-able", name, tt)
}
Defensive patterns

Strategy: validation

Validate before calling

var tt string
if err := conn.QueryRow(ctx, "select typtype::text from pg_type where typname=$1", name).Scan(&tt); err != nil { return err }
switch tt {
case "b","c","d","e","r","m":
    // LoadType-able
default:
    return fmt.Errorf("type %s has typtype %q; pgx cannot LoadType it", name, tt)
}
return nil

Type guard

func loadTypeable(tt string) bool {
    switch tt {
    case "b","c","d","e","r","m": return true
    }
    return false
}

Try / catch

if t, err := conn.LoadType(ctx, name); err != nil {
    if strings.Contains(err.Error(), "unknown typtype") {
        // not a LoadType-able type; skip
        return nil, nil
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling Conn.LoadType on a pseudo-type (e.g. 'record', 'anyelement', 'trigger', 'void'), a table's implicit row type, or a brand-new kind of type added by a future/extension PostgreSQL version.

Common situations: Trying to LoadType a table name (row types are 'c' composites only for CREATE TYPE AS composites; tables expose row types that LoadType does not model); pointing LoadType at 'anyelement'/generic types; an extension introducing a novel typtype.

Related errors


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