{"id":"c9af74057626796d","repo":"psycopg/psycopg2","slug":"postgresql-range-name-not-found","errorCode":null,"errorMessage":"PostgreSQL range '{name}' not found","messagePattern":"PostgreSQL range '(.+?)' not found","errorType":"exception","errorClass":"ProgrammingError","httpStatus":null,"severity":"error","filePath":"lib/_range.py","lineNumber":410,"sourceCode":"join pg_namespace ns on ns.oid = typnamespace\nWHERE t.oid = %s::regtype\n\"\"\", (name, ))\n            except ProgrammingError:\n                pass\n            else:\n                rec = curs.fetchone()\n                if rec:\n                    tname, schema = rec[3:]\n            finally:\n                if savepoint:\n                    curs.execute(\"ROLLBACK TO SAVEPOINT register_type\")\n\n        # revert the status of the connection as before the command\n        if conn_status != STATUS_IN_TRANSACTION and not conn.autocommit:\n            conn.rollback()\n\n        if not rec:\n            raise ProgrammingError(\n                f\"PostgreSQL range '{name}' not found\")\n\n        type, subtype, array = rec[:3]\n\n        return RangeCaster(name, pyrange,\n            oid=type, subtype_oid=subtype, array_oid=array)\n\n    _re_range = re.compile(r\"\"\"\n        ( \\(|\\[ )                   # lower bound flag\n        (?:                         # lower bound:\n          \" ( (?: [^\"] | \"\")* ) \"   #   - a quoted string\n          | ( [^\",]+ )              #   - or an unquoted string\n        )?                          #   - or empty (not catched)\n        ,\n        (?:                         # upper bound:\n          \" ( (?: [^\"] | \"\")* ) \"   #   - a quoted string\n          | ( [^\"\\)\\]]+ )           #   - or an unquoted string\n        )?                          #   - or empty (not catched)","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/psycopg/psycopg2/blob/3a6d9d6ddc6b53eaa80b712f5fa6b23abbdc38db/lib/_range.py#L392-L428","documentation":"Raised by RangeCaster._from_db() (lib/_range.py:409-411) after both lookup strategies against pg_range/pg_type fail to find a range type with the given name in the given schema. The first query filters by typname and namespace; a fallback (lib/_range.py:388-400) uses '%s::regtype' to respect search_path. If neither returns a row, the type does not exist or is not visible.","triggerScenarios":"Calling register_range('nonexistent', pyrange, conn), or passing a schema-qualified name where the schema or type is misspelled, or registering a type that is a plain type (not a range), or a range defined in a schema not on the connection's search_path and not schema-qualified correctly.","commonSituations":"Typos in the type name, wrong schema qualification, connecting as a different role that lacks USAGE privilege on the schema, or assuming a custom range type exists when the migration that creates it hasn't run.","solutions":["Verify the type exists and is a range: run \"SELECT rngtypid FROM pg_range JOIN pg_type t ON t.oid=rngtypid WHERE typname='X';\".","Schema-qualify the name if it lives outside search_path: register_range('myschema.myrange', ...).","Ensure the migration creating the range type (CREATE TYPE ... AS RANGE) has been applied on this database.","Check that the connecting role has USAGE privilege on the owning schema."],"exampleFix":"// before\nregister_range('myrang', MyRange, conn)  # typo\n// after\nregister_range('appschema.myrange', MyRange, conn)","handlingStrategy":"validation","validationCode":"with conn.cursor() as c:\n    c.execute(\"SELECT 1 FROM pg_range r JOIN pg_type t ON t.oid=r.rngtypid \"\n              \"JOIN pg_namespace n ON n.oid=t.typnamespace \"\n              \"WHERE t.typname=%s\", (name.split('.')[-1],))\n    if c.fetchone() is None:\n        raise ValueError(f'range type {name!r} does not exist')","typeGuard":"def range_type_exists(conn, name: str) -> bool:\n    with conn.cursor() as c:\n        c.execute(\"SELECT EXISTS(SELECT 1 FROM pg_range r JOIN pg_type t \"\n                  \"ON t.oid=r.rngtypid WHERE t.typname=%s)\", (name.split('.')[-1],))\n        return bool(c.fetchone()[0])","tryCatchPattern":"try:\n    caster = register_range(name, pyrange, conn)\nexcept ProgrammingError as e:\n    if 'not found' in str(e):\n        # create the type or skip\n        pass\n    else: raise","preventionTips":["Run the CREATE TYPE migration before registering range casters.","Schema-qualify custom range type names to avoid search_path ambiguity.","Verify role has USAGE on the schema hosting the range type."],"tags":["range","postgresql","type-not-found","schema","programming-error"],"analyzedSha":"3a6d9d6ddc6b53eaa80b712f5fa6b23abbdc38db","analyzedAt":"2026-08-04T19:56:51.958Z","schemaVersion":2}