Skip to content

Fix IndexError in URL.replace() on a URL with no authority#3317

Merged
Kludex merged 2 commits into
Kludex:mainfrom
LeSingh1:fix/url-replace-empty-netloc
Jun 10, 2026
Merged

Fix IndexError in URL.replace() on a URL with no authority#3317
Kludex merged 2 commits into
Kludex:mainfrom
LeSingh1:fix/url-replace-empty-netloc

Conversation

@LeSingh1

@LeSingh1 LeSingh1 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

URL.replace() raises IndexError when you change an authority component on a URL that has no authority. This happens for path-only URLs, where the netloc is empty.

A small reproduction:

from starlette.datastructures import URL

URL("/path").replace(port=8080)      # IndexError: string index out of range
URL("/path").replace(username="u")   # IndexError: string index out of range

The cause is in the branch that derives the existing hostname when the caller does not pass one. The netloc is empty, so after rpartition("@") the hostname is also empty, and the bracket check then indexes an empty string:

if hostname[-1] != "]":
    hostname = hostname.rsplit(":", 1)[0]

This guards that check so the split is only attempted when there is a hostname to split. A path-only URL now gains the requested component in its netloc instead of crashing, which matches what already happens when you pass hostname explicitly:

URL("/path").replace(hostname="h", port=8080)  # "//h:8080/path", already works
URL("/path").replace(port=8080)                # now "//:8080/path", was IndexError

I added assertions to the existing test_url test covering the port and username cases on a URL with no authority. The new cases fail with IndexError before the change and pass after it. ruff check and ruff format --check both pass on the touched files.

URL.replace() raised IndexError when changing an authority component
(port, username, or password) on a URL with an empty netloc, such as a
path-only URL. The hostname derived from the empty netloc was an empty
string, and indexing it with hostname[-1] failed.

Guard the bracket check so the rsplit is skipped when hostname is empty.
A path-only URL now gains the requested component in its netloc instead
of crashing.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Tip: cubic could auto-approve low-risk PRs like this, if it thinks it's safe to merge. Learn more

Re-trigger cubic

@Kludex Kludex enabled auto-merge (squash) June 10, 2026 06:45
@Kludex Kludex merged commit 1a2f972 into Kludex:main Jun 10, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants