ruby/ruby · error · InvalidURIError

bad URI (absolute but no path): #{uri}

Error message

bad URI (absolute but no path): #{uri}

What it means

The RFC 2396 parser captured a scheme but found nothing after the colon — no path, no opaque part, and no host or registry. 'scheme:' alone is not an absolute URI under RFC 2396, so split raises 'bad URI (absolute but no path)'.

Source

Thrown at lib/uri/rfc2396_parser.rb:146

        # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]

        # absoluteURI   = scheme ":" ( hier_part | opaque_part )
        # hier_part     = ( net_path | abs_path ) [ "?" query ]
        # opaque_part   = uric_no_slash *uric

        # abs_path      = "/"  path_segments
        # net_path      = "//" authority [ abs_path ]

        # authority     = server | reg_name
        # server        = [ [ userinfo "@" ] hostport ]

        if !scheme
          raise InvalidURIError,
            "bad URI (absolute but no scheme): #{uri}"
        end
        if !opaque && (!path && (!host && !registry))
          raise InvalidURIError,
            "bad URI (absolute but no path): #{uri}"
        end

      when @regexp[:REL_URI]
        scheme = nil
        opaque = nil

        userinfo, host, port, registry,
          rel_segment, abs_path, query, fragment = $~[1..-1]
        if rel_segment && abs_path
          path = rel_segment + abs_path
        elsif rel_segment
          path = rel_segment
        elsif abs_path
          path = abs_path
        end

        # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]

View on GitHub (pinned to 0e5b888e1c)

Solutions

  1. Check the interpolated remainder is non-empty before parsing
  2. Switch to the default RFC 3986 parser (URI.parse/URI()), which accepts 'http:' with an empty path
  3. Reject scheme-only strings with a dedicated regexp and a clear domain error

Example fix

# before
uri = URI::Parser.new.parse("#{scheme}:#{rest}")   # rest = ""
# InvalidURIError: bad URI (absolute but no path)

# after
raise ArgumentError, "missing part after scheme '#{scheme}:'" if rest.to_s.empty?
uri = URI.parse("#{scheme}:#{rest}")
Defensive patterns

Strategy: validation

Validate before calling

BARE_SCHEME = /\A[A-Za-z][A-Za-z0-9+.-]*:\z/
def complete_uri?(s)
  !BARE_SCHEME.match?(s.to_s)
end

Try / catch

begin
  parser.parse(str)
rescue URI::InvalidURIError
  raise ArgumentError, "URI is scheme-only, nothing after the colon: #{str}"
end

Prevention

When it happens

Trigger: URI::Parser.new.parse('http:'); parser.split('ftp:'); interpolated URIs like "#{scheme}:#{rest}" where rest is empty.

Common situations: Template-built URIs with an empty remainder; config values reduced to a bare scheme; validation code routing scheme-only strings through the legacy parser.

Related errors


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