{"id":24037,"library":"miniupnpc","title":"miniupnpc","description":"Python bindings for the MiniUPnP library, used to control UPnP-enabled Internet Gateway Devices (IGD) for port forwarding and NAT traversal. Version 2.3.3 is the latest release; updates are infrequent (months to years between releases).","status":"active","version":"2.3.3","language":"python","source_language":"en","source_url":"https://github.com/miniupnp/miniupnp/tree/master/miniupnpc","tags":["UPnP","IGD","port forwarding","NAT traversal","networking"],"install":[{"cmd":"pip install miniupnpc","lang":"bash","label":"PyPI install"}],"dependencies":[{"reason":"System shared library (libminiupnpc). Usually included with the Python package, but may need separate installation on some platforms.","package":"miniupnpc","optional":true},{"reason":"Required at build time when installing from source.","package":"setuptools","optional":true}],"imports":[{"note":"UPnP is a class inside the module, not a top-level function. Some old examples use import miniupnpc; upnp = miniupnpc.UPnP(), which still works but is less clean.","wrong":"import miniupnpc (and then accessing .UPnP)","symbol":"UPnP","correct":"from miniupnpc import UPnP"}],"quickstart":{"code":"from miniupnpc import UPnP\nimport os\n\nupnp = UPnP()\nupnp.discoverdelay = 200\nupnp.discover()\nupnp.selectigd()\n\nprint(f\"External IP: {upnp.externalipaddress()}\")\nprint(f\"Internal IP: {upnp.lanaddr}\")\n\n# Add a port mapping\nupnp.addportmapping(\n    8888,      # external port\n    'TCP',\n    upnp.lanaddr,\n    8888,      # internal port\n    'test mapping',\n    ''         # remote host (empty = any)\n)\nprint('Port mapping added')\n\n# Remove mapping\nupnp.deleteportmapping(8888, 'TCP')\nprint('Port mapping removed')","lang":"python","description":"Discover UPnP device, get external IP, add and remove a TCP port mapping."},"warnings":[{"fix":"Use `upnp.addportmapping(port, 'TCP', internal_ip, internal_port, desc, '')` — last argument must be a string.","message":"In version 2.x, `addportmapping()` requires the remote host argument as an empty string (not None). Passing None may cause a TypeError.","severity":"breaking","affected_versions":">=2.0"},{"fix":"Use `upnp.getgenericportmapping(index)` for numbered mappings or `upnp.getspecificportmappingentry(external_port, protocol)` for a specific rule.","message":"The `UPnP.getstatus()` method (available in older 1.x) is removed in 2.x. Use `UPnP.getspecificportmappingentry()` or iterate mappings.","severity":"deprecated","affected_versions":"<2.0"},{"fix":"After `discover()`, check `if num > 0:` before calling `selectigd()`, otherwise it may raise a runtime error or silently fail.","message":"`UPnP.discover()` returns the number of devices found, but does not throw on zero devices. Always check the return value to avoid later errors.","severity":"gotcha","affected_versions":"all"},{"fix":"Call `deleteportmapping()` or use a `try/finally` block to remove mappings when done.","message":"Port mappings added via `addportmapping()` may persist on the router even after your program exits. Always clean up if you don't want permanent rules.","severity":"gotcha","affected_versions":"all"},{"fix":"Check the return code of `addportmapping()` (0 = success, non-zero = failure) and log it. Use diagnostic tools like `upnpc -a` from the command line if available.","message":"Some routers reject mappings from IPs not on the same subnet, or have maximum mapping limits. The library does not validate this, so you may get silent failures.","severity":"gotcha","affected_versions":"all"},{"fix":"Upgrade to Python 3.5+.","message":"Python 2 support was dropped in version 2.0. Python 3.4+ (now 3.5+) is required.","severity":"breaking","affected_versions":">=2.0","deprecated_versions":"<2.0 (but deprecated)"},{"fix":"Always provide a description string, even if empty. Use `upnp.addportmapping(port, proto, int_ip, int_port, 'mapping')`.","message":"The `addportmapping` method's `desc` argument was previously optional; now it is required (type: str). Passing no description will cause a TypeError.","severity":"deprecated","affected_versions":">=2.3"}],"env_vars":null,"last_verified":"2026-05-01T00:00:00.000Z","next_check":"2026-07-30T00:00:00.000Z","problems":[{"fix":"Use `from miniupnpc import UPnP` instead of importing the module and accessing the attribute.","cause":"Trying to import with `import miniupnpc` and then using `miniupnpc.UPnP()` without checking the import path. In some distributions (e.g., Debian), the package provides `miniupnpc.UPnP` correctly, but on some wheels the class is exposed only if imported as `from miniupnpc import UPnP`.","error":"AttributeError: module 'miniupnpc' has no attribute 'UPnP'"},{"fix":"Install the library via `pip install miniupnpc` (or `python -m pip install miniupnpc` if pip is not in PATH).","cause":"The miniupnpc library is not installed, or you are using a virtual environment without the package.","error":"ImportError: No module named miniupnpc"},{"fix":"Ensure indices are integers, not strings. For example, use `for i in range(upnp.getportmappingnumberofentries()):` then `upnp.getgenericportmapping(i)`.","cause":"Calling a method that expects an integer index with a string, e.g., `upnp.getgenericportmapping('0')` instead of `upnp.getgenericportmapping(0)`. This often happens when iterating over discovered devices or ports.","error":"TypeError: string indices must be integers"},{"fix":"Verify you are on a network with a UPnP-enabled router. Try running the `upnpc` command-line tool from the miniupnpc package to confirm discovery works.","cause":"The UPnP device (router) is not reachable, or the machine is on a network without UPnP support (e.g., some public WiFi or VPN).","error":"URLError: <urlopen error [Errno 101] Network is unreachable>"}],"ecosystem":"pypi","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null}