Skip to content

[fix] inconsistent space encoding in query params#14691

Merged
sfc-gh-lwilby merged 1 commit intodevelopfrom
fix/gh-14671
Apr 9, 2026
Merged

[fix] inconsistent space encoding in query params#14691
sfc-gh-lwilby merged 1 commit intodevelopfrom
fix/gh-14671

Conversation

@sfc-gh-lwilby
Copy link
Copy Markdown

@sfc-gh-lwilby sfc-gh-lwilby commented Apr 8, 2026

Summary

Fixes #14671

Root cause: The frontend bind="query-params" path uses queryString.stringify() (which internally uses encodeURIComponent, encoding spaces as %20), while the backend st.query_params path uses urllib.parse.urlencode() (which uses quote_plus, encoding spaces as +). When both paths interact, the URL flips between %20 and + encoding.

Fix: Post-process the output of queryString.stringify() with .replaceAll("%20", "+") in both buildBoundQueryParams() and updateUrlParam() to align with the backend's + encoding convention.

Changes

  • WidgetStateManager.ts: Replace %20 with + in the output of both queryString.stringify() call sites
  • WidgetStateManager.test.ts: Add 2 tests verifying spaces encode as + (not %20) in both the URL update and page change filter paths

Test plan

  • New unit tests: "encodes spaces as + in URL, not %20" and "encodes spaces as + in filterParamsForPageChange, not %20"
  • All 146 existing WidgetStateManager tests pass

Made with Cursor

Align frontend bind="query-params" encoding to use + for spaces instead
of %20, matching the backend st.query_params convention. Previously,
frontend used encodeURIComponent (%20) while backend used
urllib.parse.urlencode (+), causing confusing URL changes when both
paths interacted.

Fixes #14671

Made-with: Cursor

Co-authored-by: lawilby <laura.wilby+oss@snowflake.com>
@snyk-io
Copy link
Copy Markdown
Contributor

snyk-io Bot commented Apr 8, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

✅ PR preview is ready!

Name Link
📦 Wheel file https://core-previews.s3-us-west-2.amazonaws.com/pr-14691/streamlit-1.56.0-py3-none-any.whl
📦 @streamlit/component-v2-lib Download from artifacts
🕹️ Preview app pr-14691.streamlit.app (☁️ Deploy here if not accessible)

@sfc-gh-lwilby sfc-gh-lwilby added change:bugfix PR contains bug fix implementation impact:users PR changes affect end users labels Apr 8, 2026
@sfc-gh-lwilby sfc-gh-lwilby marked this pull request as ready for review April 8, 2026 18:04
Copilot AI review requested due to automatic review settings April 8, 2026 18:04
@sfc-gh-lwilby sfc-gh-lwilby added the ai-review If applied to PR or issue will run AI review workflow label Apr 8, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes inconsistent URL space encoding when query params are written from both the frontend bind="query-params" flow and the backend st.query_params flow by aligning the frontend encoding to the backend’s +-for-space convention.

Changes:

  • Post-process query-string output to replace %20 with + when building query strings for bound widget params and when updating the URL.
  • Add unit tests to ensure spaces are encoded as + (and never %20) for both URL updates and filterParamsForPageChange.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
frontend/lib/src/WidgetStateManager.ts Normalizes space encoding by converting %20+ after queryString.stringify() in the two relevant query-string construction paths.
frontend/lib/src/WidgetStateManager.test.ts Adds coverage verifying the URL and page-change filtering paths encode spaces as + (not %20).

@github-actions github-actions Bot removed the ai-review If applied to PR or issue will run AI review workflow label Apr 8, 2026
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Summary

This PR fixes inconsistent space encoding in URL query parameters when using bind="query-params" on widgets. The frontend's query-string library encodes spaces as %20 (via encodeURIComponent), while the backend's urllib.parse.urlencode uses +. This mismatch caused the browser URL to visually flip between %20 and + encoding when both frontend widgets and backend st.query_params interact.

The fix post-processes queryString.stringify() output with .replaceAll("%20", "+") at both call sites in WidgetStateManager.tsfilterParamsForPageChange() (for page navigation) and updateUrlParam() (for live URL sync). Two new unit tests verify the corrected encoding.

Reviewer consensus: All three reviewers (claude-4.6-opus-high-thinking, gemini-3.1-pro, gpt-5.3-codex-high) approved this PR unanimously with no blocking issues or disagreements.

Code Quality

The fix is well-targeted, minimal, and follows existing patterns in the codebase. All reviewers agreed on this assessment. Only the two queryString.stringify() call sites that produce browser-visible URL strings are patched — the unrelated queryString.stringifyUrl() in ComponentInstance.tsx (for custom component iframe src) is correctly left untouched.

The .replaceAll("%20", "+") approach is safe because encodeURIComponent only produces %20 from actual space characters (literal %20 in a value would be double-encoded as %2520), and + signs in values are correctly preserved as %2B. Roundtrip correctness is maintained: query-string v9's parse() replaces + with space before decoding, so values survive the parse-modify-stringify cycle without corruption.

The inline comments explaining the replaceAll intent ("to match backend urllib.parse.urlencode encoding") are appropriate — they document the why, not the what.

Test Coverage

All reviewers agreed that test coverage is adequate. The PR adds two new unit tests to WidgetStateManager.test.ts:

  • "encodes spaces as + in URL, not %20" — tests the updateUrlParam path
  • "encodes spaces as + in filterParamsForPageChange, not %20" — tests the page navigation path

Both tests use positive + negative assertions (asserting + is present AND %20 is absent), following anti-regression testing best practices. The test mock setup correctly tracks URL state across replaceState calls.

No new e2e test is necessary — the fix is a mechanical encoding normalization where both + and %20 are semantically equivalent, and the existing e2e suite for query params would catch any functional regressions.

Backwards Compatibility

No breaking changes — all three reviewers concur. Both + and %20 are valid space representations in URL query strings per RFC 3986 and the application/x-www-form-urlencoded specification. The backend (urllib.parse.parse_qs) handles both forms correctly. Existing URLs containing %20 remain parseable; subsequent frontend writes now canonicalize spaces to +. The only observable change is cosmetic: the browser URL bar will now consistently show + instead of sometimes showing %20.

Security & Risk

No security concerns — unanimous agreement across all reviewers. The change is purely cosmetic URL encoding normalization. It does not affect data transmitted to the backend, authentication, session management, CSRF handling, external resource loading, or cross-origin behavior. Regression risk is low and limited to query-string serialization behavior, which is directly covered by the new tests.

External test recommendation

  • Recommend external_test: No
  • Triggered categories: None
  • Evidence:
    • frontend/lib/src/WidgetStateManager.ts: Only changes URL query parameter encoding (cosmetic normalization of %20 to +), no routing, auth, WebSocket, embedding, or security-sensitive behavior changes
  • Suggested external_test focus areas: N/A
  • Confidence: High (all three reviewers independently reached the same conclusion)
  • Assumptions and gaps: None — the change is purely frontend-side URL string normalization with no server, networking, or cross-origin implications.

Accessibility

No accessibility impact. All reviewers agree. This PR changes URL encoding behavior only — no UI elements, ARIA attributes, focus management, keyboard interactions, or semantic structure are affected.

Recommendations

No blocking issues. One optional suggestion was raised:

  1. Optional (claude-4.6-opus-high-thinking only): Consider adding an explicit roundtrip unit test that sets a space-containing value, then updates a different widget, and verifies the original space value is still encoded as + (not %2B or %20). This would directly exercise the parse → modify → stringify → replaceAll cycle for space values. The other two reviewers did not raise this, and the existing test coverage is sufficient.

Verdict

APPROVED: All three reviewers (3/3) unanimously approved. The fix is clean, well-scoped, correctly normalizes frontend space encoding in query parameters to match the backend's + convention, and includes appropriate regression tests with no backwards compatibility or security concerns.


This is a consolidated AI review by claude-4.6-opus-high-thinking, synthesizing reviews from: claude-4.6-opus-high-thinking, gemini-3.1-pro, gpt-5.3-codex-high. All expected models completed their reviews successfully.

@sfc-gh-lwilby sfc-gh-lwilby changed the title Fix inconsistent space encoding in query params [fix] inconsistent space encoding in query params Apr 8, 2026
Copy link
Copy Markdown
Collaborator

@lukasmasuch lukasmasuch left a comment

Choose a reason for hiding this comment

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

LGTM 👍

@sfc-gh-lwilby sfc-gh-lwilby merged commit ec8f0b6 into develop Apr 9, 2026
92 of 93 checks passed
@sfc-gh-lwilby sfc-gh-lwilby deleted the fix/gh-14671 branch April 9, 2026 09:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:bugfix PR contains bug fix implementation impact:users PR changes affect end users

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inconsistent space encoding in query params / Encode spaces as + with bind="query-params"

4 participants