Your Android OpenVPN profile fails to add a route because the phone holds no address on the virtual interface, so there is nothing for a route to point at. Routes answer only where packets should go. The tunnel address answers who the phone is inside the tunnel, and the client must supply one before the interface can exist. Work through the four checks below in order and stop at the first failure, because editing routes before the address exists hides the real problem.

Read the failure in the order the client executes it

Android's VpnService.Builder keeps the two concepts apart: addAddress() puts an address on the interface the app is building, addRoute() adds a destination prefix, and establish() refuses to create the interface until at least one address has been added. An OpenVPN client maps the profile and the options pushed by the server onto exactly those calls, so a connection that never parses an address cannot build the interface at all.

That is why the log line you are reading may name a route while the cause sits one step earlier. The client reaches the route stage only after the interface exists; with no address, the route call fails immediately or never runs. When the log says it cannot add a route, start with the address rather than the route syntax.

Check 1: does the server put an address in the reply?

For a routed OpenVPN service the address comes from the server pool or from a per-client assignment, and the topology decides what shape it has. On an OpenVPN 2.4 or later server, a subnet-topology service looks like this:

topology subnet
server 10.8.0.0 255.255.255.0
client-config-dir ccd

With that shape the server pushes something like ifconfig 10.8.0.6 255.255.255.0. An older topology net30 deployment pushes a peer address instead, for example ifconfig 10.8.0.6 10.8.0.5, so a profile moved between the two models can look correct while carrying the wrong netmask.

Search the client connection log for the pushed option set. If it holds no ifconfig line at all, the server never sent an address or the client declined the option. On a server that uses client-config-dir, the file named after the common name on the certificate has to exist and carry the assignment:

# ccd/phone-anna
ifconfig-push 10.8.0.6 255.255.255.0

Check 2: does the client keep the address it was given?

A filter that is too broad is the second common cause. pull-filter exists in OpenVPN 2.4 and later, and when several filters match the same option the last matching one wins, so a trailing catch-all removes the address without an error:

# removes every pushed option, including the address
pull-filter ignore "ifconfig"
pull-filter ignore "route"

Narrow the filter to the option you actually want gone and leave the address alone:

# keeps the pushed address, drops one unwanted LAN route
pull-filter ignore "route 10.60.0.0"

Advice to disable all pulls usually comes from someone trying to get rid of a single route. route-nopull is the narrower switch: it keeps ifconfig and the other pushed options while declining pushed routes and DHCP-style options. Use it when that is genuinely what you want, and answer the address question separately.

Check 3: is the address yours to type?

Manual addressing is legitimate only when the operator hands you the value. If you type one yourself it has to come from the VPN client subnet, be unique among active sessions and match the topology the server runs. Copying the address of a desktop bridge or a host on the remote LAN fails on both counts: the phone would claim an address that already exists elsewhere, and the gateway would have no return path to it.

The remote LAN prefix in a route is a destination, never the identity of the phone. A route for 10.60.0.0/24 says reach that network through the tunnel; it says nothing about which 10.60.0.x address the phone should hold, and the phone should hold none of them. Static assignments belong on the server side, where they cannot collide with the dynamic pool.

Two sessions on one identity expose the same collision. If the same certificate connects twice and the server pushes one fixed address to both, the second session duplicates the first, and separate identities or separate assignments are the fix rather than a client-side edit.

Check 4: is something else holding the tunnel slot?

Android allows one active VPN service at a time. Another VPN app, or an always-on VPN entry left enabled for a profile that no longer works, can take that slot before your OpenVPN client calls establish(). The interface then never appears even though the profile is valid, so disconnect the other VPN, switch the always-on setting off and reconnect before you touch the profile.

A service that insists on Ethernet bridging is the other dead end. A non-root Android app can create an IP tunnel, not a bridged Ethernet segment, so no address you type will make a dev tap server work; the operator has to offer a routed service. When you report the problem, include the client name and version, the pushed option set, the topology and the exact step where the address should have appeared.

If all four checks pass and the address is present, unique and correctly masked, the route question becomes the ordinary one: which prefixes the server authorizes and how the client should scope them. Write down the tunnel address, its netmask and the topology before you change anything else, because those three values are what the operator needs to compare against the server view.

Artaigilean co-cheangailte