cookie-import-browser: profile pills show stale creation-time names (11 Brave profiles → 5 labels, five reading "Profile 1")
- Dominant language
- TypeScript
- Stars
- 133k
- Forks
- 19.9k
- Avg merge
- 18h 46m
- Merged PRs (30d)
- 26
Description
## Summary
The cookie picker's profile pills read profile display names from the wrong file. On Brave, 11 distinct profiles render as only 5 distinct labels, including five pills all reading "Profile 1". You cannot tell which profile you are about to import cookies from.
Root cause: `listProfiles()` reads `/Preferences` → `profile.name`, a legacy per-profile field that Chromium seeds at profile creation and does not update on rename. The authoritative display name lives at browser level in `Local State` → `profile.info_cache[].name`, which is what the browser's own profile switcher renders.
## Repro
1. Use Brave with several profiles renamed via the profile menu.
2. Run `browse cookie-import-browser`.
3. Select **Brave** as the source browser.
4. Observe the profile pills row.
## Evidence
Brave's own profile menu, all 11 names correct:
The picker for the same 11 profiles:
Calling the shipped `listProfiles()` directly:
```
dir Local State (truth) listProfiles() displayName
------------------------------------------------------------------
Default Personal "Personal" OK
Profile 5 Springboro Festivals "Profile 1"
Profile 6 Brian Retterer "Brian Retterer" OK
Profile 16 Boro After Prom "Profile 1"
Profile 17 Families of SHS "Profile 1"
Profile 18 Foster "Profile 1"
Profile 19 Warren County Astro "Profile 1"
Profile 22 Springboro Juneteenth "Person 1"
Profile 23 Artfest "Your Brave"
Profile 24 Collab Connect "Your Brave"
Profile 25 Ticket Committee "Person 1"
Ambiguous labels: "Profile 1" x5, "Person 1" x2, "Your Brave" x2
Total profiles: 11, distinct labels: 5
```
## Why the stale values look like this
The wrong labels are fossils of each profile's auto-generated name at creation time. They correlate exactly with the Brave build that created the profile:
```
created_by_version stale prefs_name
119.1.60.x 'Profile 1'
120.1.61.116 'Profile 1'
133.1.75.178 'Person 1'
137.1.79.118 'Your Brave'
138.1.80.120 'Your Brave'
148.1.90.122 'Person 1'
```
Those are Brave's default new-profile names across those eras. This confirms `Preferences` → `profile.name` is written once at creation and never refreshed on rename.
Supporting detail: only the two profiles that render correctly carry a `using_default_name: False` key in their own `Preferences`. The other nine have no such key. Meanwhile `Local State` → `info_cache` has `is_using_default_name: False` and the correct name for all 11. Two profiles created by the *same* build (Profile 5 and Profile 6) differ here, so this is about which rename path was used, not browser version.
## Why this survived
On Chrome the bug is usually masked. Signed-in Chrome profiles populate `account_info[0].email`, so the earlier branch in `listProfiles()` fires and yields a readable email. Brave has no Google sign-in, so `account_info` is always absent and every profile falls through to the stale field. In practice this is close to Brave-specific, which is the kind of gap that escapes Chrome-based testing.
## Impact
Not cosmetic. The picker's whole purpose is choosing which profile's cookies to import. With five identical "Profile 1" pills, selecting the intended profile is guesswork, and picking wrong imports the wrong session cookies into the headless browser: wrong account, wrong org, credentials the user did not intend to expose to an automated session.
## Origin
`listProfiles()` and the `account_info` lookup entered the tree in `22a4451` (v1.3.0.0). The design matches PR #121 ("Add profile picker to cookie import UI"), whose description states the premise directly:
> Profile display names are read from each profile's `Preferences` JSON (the same name shown in the browser's profile switcher), falling back to the directory name if unavailable.
That parenthetical is the defect. `Preferences` → `profile.name` is not the name in the profile switcher. So this is a mistaken assumption rather than a deliberate tradeoff. The described fallback does work as written, but never triggers, because the stale field is always present and always looks valid.
## Fix
Prefer `Local State` → `info_cache[dir].name`, falling back to the existing logic. `Local State` is already read in this same file (around line 492, for the v10 encryption key), so path resolution is proven.
In `browse/src/cookie-import-browser.ts`, `listProfiles()`:
```ts
// once, before the entry loop
let infoCache: Record = {};
try {
infoCache = JSON.parse(fs.readFileSync(path.join(browserDir, 'Local State'), 'utf-8'))
?.profile?.info_cache ?? {};
} catch { /* fall through to per-profile Preferences */ }
// inside the loop, ahead of the Preferences read
const cached = infoCache[entry.name]?.name;
if (typeof cached === 'string' && cached) {
displayName = cached;
} else {
// existing account_info / profile.name fallback
}
```
## Secondary nit (same area)
PR #121 describes the list as "sorted Default-first", but the returned order is raw `readdirSync` order: `Profile 17, 19, 18, 16, 6, Default, 22, 25, 24, 23, 5`. The pills render in that order, so `Default` lands sixth and the numbered profiles are not in numeric order. Selection is unaffected (the UI correctly auto-selects `Default`), so this is display ordering only. A sort would make the row much easier to scan.
## Environment
- gstack v1.69.0.0 (`ad84005`, at `origin/HEAD`, 0 commits behind)
- macOS 15 (Darwin 25.5.0), x64
- Brave Browser, 11 profiles
- Also affects Chrome installs where profiles are not signed in
---
🤖 Root cause investigation and this report drafted with [Claude Code](https://claude.com/claude-code). All findings (the `Local State` vs `Preferences` divergence, the `created_by_version` correlation, and the `listProfiles()` output) were verified directly against a live Brave install rather than inferred.
Contributor guide
Research direction
Start in browse/src/cookie-import-browser.ts at listProfiles() and inspect the existing Local State read and per-profile Preferences fallback. Reproduce with `browse cookie-import-browser` using Brave profiles, then verify that the profile pills use Local State info_cache names and retain the fallback when unavailable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli, frontend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100