AttributeError: ‘NoneType’ Object Has No Attribute ‘To_Capabilities’ | Fast, Reliable Fixes

This error means your driver “options” object is None; pass a real options instance or load capabilities correctly to start the session.

Seeing this stack trace in Python can stall any mobile or browser test run. The root is simple: Selenium’s remote session builder expects an options object that can produce W3C capabilities. When it receives None, the call to to_capabilities() fails and you get the message above. The good news: a few clean adjustments fix it for Appium (Android/iOS), local Selenium, and grid/cloud runs.

Why You See AttributeError: ‘NoneType’ Object Has No Attribute ‘To_Capabilities’

Quick context: In Selenium 4, sessions are created from browser or driver options. Internally, Selenium calls options.to_capabilities() to produce the payload. If your code passes options=None or a wrong type, None has no such method, so the call crashes. Appium’s Python client integrates with Selenium’s flow, so the same rule applies across Android, iOS, and mobile web.

What “None” usually means: a variable named options never got assigned, a helper returned None, or you used a legacy desired_capabilities=... path that no longer wires options in Selenium 4.

Quick Checks Before You Change Code

  • Print The Variable — Add print(type(options)) right before webdriver.Remote(...). If you see <class 'NoneType'>, you found the cause.
  • Pick The Right Options Class — Use the exact class that matches your target:
    • Android (Appium): from appium.options.android import UiAutomator2Options
    • iOS (Appium): from appium.options.ios import XCUITestOptions
    • Desktop Chrome: from selenium.webdriver.chrome.options import Options
    • Edge/Firefox/Safari: their matching Options classes
  • Avoid Mixed Paths — Don’t pass both desired_capabilities=... and options=.... Stick to options only.
  • Verify Package Versions — Keep Selenium/Appium client versions that work together. Old code with new clients is a common mismatch.

Fix Attributeerror ‘Nonetype’ Object Has No Attribute ‘To_Capabilities’ — By Setup

Android With Appium (UiAutomator2)

Use UiAutomator2Options, then .load_capabilities() if you want to keep a dict, or set fields directly on the options object.

from appium import webdriver
from appium.options.android import UiAutomator2Options

caps = {
    "platformName": "Android",
    "automationName": "UiAutomator2",
    "deviceName": "Android Emulator",
    "appPackage": "com.android.settings",
    "appActivity": ".Settings",
    "language": "en",
    "locale": "US"
}

options = UiAutomator2Options().load_capabilities(caps)
driver = webdriver.Remote("http://127.0.0.1:4723", options=options)

iOS With Appium (XCUITest)

from appium import webdriver
from appium.options.ios import XCUITestOptions

options = XCUITestOptions()
options.platformVersion = "17.0"
options.deviceName = "iPhone 15"
options.bundleId = "com.example.app"

driver = webdriver.Remote("http://127.0.0.1:4723", options=options)

Desktop Chrome (Local)

Pass a real Chrome Options object.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_argument("--start-maximized")

driver = webdriver.Chrome(options=chrome_options)

Remote Grid Or Cloud (Desktop Browser)

When pointing to a Selenium Grid or a cloud hub, you still pass a concrete options object. The hub URL changes; the pattern does not.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.set_capability("browserVersion", "latest")
chrome_options.set_capability("platformName", "Windows")

driver = webdriver.Remote("https://your.grid.or.cloud/wd/hub", options=chrome_options)

Mobile Web On Android (Chrome Under Appium)

Use Android options and add browserName.

from appium import webdriver
from appium.options.android import UiAutomator2Options

caps = {
    "platformName": "Android",
    "automationName": "UiAutomator2",
    "deviceName": "Pixel_7_Pro_API_34",
    "browserName": "Chrome"
}

options = UiAutomator2Options().load_capabilities(caps)
driver = webdriver.Remote("http://127.0.0.1:4723", options=options)

Working Examples You Can Copy

Keep Your Old Dict? Load It Into Options

# You can keep your old capability dicts.
caps = {"platformName": "Android", "automationName": "UiAutomator2", "deviceName": "Android"}
from appium.options.android import UiAutomator2Options
driver = webdriver.Remote("http://localhost:4723", options=UiAutomator2Options().load_capabilities(caps))

Set On The Options Object Directly

from appium.options.ios import XCUITestOptions
opts = XCUITestOptions()
opts.deviceName = "iPhone 14"
opts.platformVersion = "16.4"
opts.bundleId = "com.example.app"
driver = webdriver.Remote("http://localhost:4723", options=opts)

Selenium Wire, Proxies, Or Wrappers

Some wrappers change how you pass options. If a wrapper expects its own “options” type or returns None, route the underlying Selenium options explicitly. As a safe baseline, build a standard Options object first and pass it through the wrapper in the way the wrapper’s docs show.

Common Pitfalls And How To Avoid Them

  • Overwriting The Variable — Calling a method that returns None and reassigning it to options wipes the object. Keep mutations and assignment separate.
  • Using Desired Capabilities Alone — In Selenium 4, desired_capabilities is deprecated and removed in many layers. Build from Options and pass options=....
  • Mismatched Packages — New Appium client with very old Selenium, or the reverse, can break the handoff. Pin known-good pairs in requirements.txt.
  • Wrong Options ClassUiAutomator2Options for Android; XCUITestOptions for iOS; the desktop browser’s own Options for web.
  • Passing Both Options And Caps — When you pass a dict via desired_capabilities and also pass options, only one wins. Stick to the options path shown above.
  • Typos In KeysbrowserName vs browsername or a misspelled automation driver can lead to silent failures that bubble up as the same crash.

Troubleshooting Table

Symptom Likely Cause Fix
AttributeError: 'NoneType' object has no attribute 'to_capabilities' on webdriver.Remote options is None Build the correct options class and pass it via options=...
Same error after updating Appium client Switched from desired caps to options; old code path Use UiAutomator2Options()/XCUITestOptions() and .load_capabilities()
Remote/cloud run fails before session Wrong options class or missing browser fields Use browser’s Options and set browserVersion/platformName
Works locally, fails on grid Wrapper/proxy stripped your options Create native Selenium Options, then pass through wrapper as documented
Appium Android won’t start Used Selenium’s Chrome Options instead of UiAutomator2Options Switch to UiAutomator2Options or load your dict into it

Version Notes, Clean Installs, And Safe Upgrades

Selenium 4 standardized on options classes across languages. That’s why the attributeerror: ‘nonetype’ object has no attribute ‘to_capabilities’ often appears right after an upgrade or when you copy an older snippet. The cure is to migrate everything to the options pattern. The Selenium docs show options per browser, and Appium’s quickstarts show the platform-specific options classes for Android and iOS.

Fresh Setup Steps

  1. Create A New Virtual Environment — Keep test tools isolated.
  2. Install Matching Clientspip install selenium appium-python-client.
  3. Pin Versions — Add an entry like selenium==4.14.* and the appium-python-client version you validated.
  4. Switch To Options Only — Replace any desired_capabilities=... arguments with a concrete options object.
  5. Smoke-Test A Minimal Script — One page open or one activity launch proves the stack before big suites run.

Reference Patterns You Can Trust

  • Appium Android — Create UiAutomator2Options, then webdriver.Remote(server, options=opts).
  • Appium iOS — Create XCUITestOptions, then webdriver.Remote(server, options=opts).
  • Desktop Browsers — Use each browser’s Options and pass options=... locally or to a hub.

Wrap-Up: Confirm The Fix

Run your minimal script. If it launches, commit the options pattern across your suite. Keep one or two tiny samples in your repo as guardrails. That way, the next time code paths change, you won’t trip the same attributeerror: ‘nonetype’ object has no attribute ‘to_capabilities’.