ruby/ruby · error · InvalidAddressError

invalid zone identifier for address

Error message

invalid zone identifier for address

What it means

IPAddr#zone_id= assigns the zone identifier of an IPv6 address. The value must be nil (clears the zone) or a String matching the strict pattern of a percent sign followed by word characters only. Anything else - 'eth0' without %, '%eth 0' with a space, an Integer scope id - raises InvalidAddressError 'invalid zone identifier for address'.

Source

Thrown at lib/ipaddr.rb:583

  # Returns the IPv6 zone identifier, if present.
  # Raises InvalidAddressError if not an IPv6 address.
  def zone_id
    if @family == Socket::AF_INET6
      @zone_id
    else
      raise InvalidAddressError, "not an IPv6 address"
    end
  end

  # Returns the IPv6 zone identifier, if present.
  # Raises InvalidAddressError if not an IPv6 address.
  def zone_id=(zid)
    if @family == Socket::AF_INET6
      case zid
      when nil, /\A%(\w+)\z/
        @zone_id = zid
      else
        raise InvalidAddressError, "invalid zone identifier for address"
      end
    else
      raise InvalidAddressError, "not an IPv6 address"
    end
  end

  protected
  # :stopdoc:

  def begin_addr
    @addr & @mask_addr
  end

  def end_addr
    case @family
    when Socket::AF_INET
      @addr | (IN4MASK ^ @mask_addr)
    when Socket::AF_INET6

View on GitHub (pinned to 0e5b888e1c)

Solutions

  1. Prefix % when missing: zid = zid.start_with?('%') ? zid : "%#{zid}"
  2. Pass nil to clear the zone identifier
  3. Pre-validate against the accepted pattern before assigning

Example fix

# before
ip.zone_id = if_name # 'eth0' -> InvalidAddressError

# after
ip.zone_id = "%#{if_name}"
Defensive patterns

Strategy: validation

Validate before calling

zid = nil if zid.nil?
zid = "%#{zid}" if zid.is_a?(String) && !zid.start_with?('%')
raise ArgumentError, 'bad zone id' unless zid.nil? || zid.match?(/\A%\w+\z/)
ip.zone_id = zid

Type guard

def valid_zone_id?(v)
  v.nil? || (v.is_a?(String) && v.match?(/\A%\w+\z/))
end

Try / catch

begin
  ip.zone_id = zid
rescue IPAddr::InvalidAddressError => e
  errors << e.message
end

Prevention

When it happens

Trigger: ip.zone_id = 'eth0' (missing leading %); ip.zone_id = '%fe80::1' (colons are not word characters); ip.zone_id = 2 (Integer from if_nametoindex); strings with hyphens, dots, or spaces in the zone name.

Common situations: Passing interface names from Socket.getifaddrs or config straight through without the % sigil; APIs that return numeric scope ids; zone names containing '-' or '.' (e.g. 'eth0.100') which \w does not match.

Related errors


AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21). Data as JSON: /api/errors/7f6755f0beb1c129. Report an issue: GitHub.