[whatwg/url] URLSearchParams inconsistent behavior with multiple same-name parameters leads to data loss on backend (Issue #889)

Voral created an issue (whatwg/url#889)

### What problem are you trying to solve?

The current implementation of `URLSearchParams` has a significant flaw when working with multiple parameters of the same name. Both `set()` and `append()` methods ultimately result in data loss when the URL is processed by most backend frameworks (especially PHP, some Java servlets, and others).

**Current behavior:**
```javascript
const params = new URLSearchParams();
params.append('category', 'books');
params.append('category', 'movies');
params.append('category', 'music');
console.log(params.toString()); // "category=books&category=movies&category=music"
```

When this reaches a typical PHP backend:
```php
// $_GET['category'] contains only 'music' - data loss!
```

**The problem:**
- The API suggests support for multiple values via `append()`
- But the string representation is incompatible with how most backend systems handle repeated parameters
- This misleads developers into thinking they can safely use multiple values
- Results in silent data loss that's hard to debug


### What solutions exist today?

Currently, developers must implement manual workarounds:

```javascript
// Manual grouping
const groups = {};
['books', 'movies', 'music'].forEach(value => {
    groups['category'] = groups['category'] ? groups['category'] + ',' + value : value;
});
// Then manually construct: "category=books,movies,music"

// Or use array notation manually
const params = ['books', 'movies', 'music'].map(v => `category[]=${v}`).join('&');
// "category[]=books&category[]=movies&category[]=music"
```

These solutions are:
- Error-prone and require extra code
- Inconsistent across different codebases
- Not discoverable for new developers


### How would you solve it?

Add an optional parameter to the constructor for logical grouping:

```javascript
// Current behavior (default for backward compatibility)
const params1 = new URLSearchParams(); 
// OR
const params2 = new URLSearchParams({ groupMultiple: false });

// New grouped behavior
const params3 = new URLSearchParams({ groupMultiple: true });
params3.append('category', 'books');
params3.append('category', 'movies');
console.log(params3.toString()); // "category=books,movies"

// Alternative: array notation
const params4 = new URLSearchParams({ groupMultiple: 'brackets' });
params4.append('category', 'books');
params4.append('category', 'movies');
console.log(params4.toString()); // "category[]=books&category[]=movies"
```

**Additional methods could include:**
```javascript
params.getMultiple('category'); // ['books', 'movies'] - returns all values
params.toString({ groupMultiple: true }); // override default for this call
```


### Anything else?

**Why this matters:**
- Prevents silent data loss in production applications
- Aligns with how form data with multiple checkboxes typically works
- Provides a migration path from current behavior
- Makes the API actually useful for real-world form handling

**Backward compatibility:**
- Default behavior remains unchanged (`groupMultiple: false`)
- New behavior is opt-in via constructor parameter
- No breaking changes for existing code

This would make `URLSearchParams` actually practical for handling form data with multiple selections, rather than being a footgun that looks like it supports multiple values but actually doesn't work with common backend systems.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/url/issues/889
You are receiving this because you are subscribed to this thread.

Message ID: <whatwg/url/issues/889@github.com>

Received on Wednesday, 22 October 2025 04:46:11 UTC