moonD4rk/HackBrowserData · error

--data-dir %q has no per-browser subdir but keys has %d brow

Error message

--data-dir %q has no per-browser subdir but keys has %d browsers; point it at the archive root, or use -b <browser> for one browser's User Data (have: %s)

What it means

BuildFromDump's layout probe (isArchiveLayout) determined the data dir has no per-browser subdirectories, yet the filtered keys dump carries more than one browser vault, so there is no unambiguous way to bind each key set to a profile directory. This is an ambiguity guard: single-vault data dirs are fine raw, but multi-vault requires the conventional archive layout (e.g. a User Data root with per-browser subdirs) or an explicit -b filter to narrow to exactly one browser.

Source

Thrown at browser/keydump.go:91

	var selected []masterkey.Vault
	for _, v := range dump.Vaults {
		if filter != "" && !strings.EqualFold(v.Browser, filter) {
			continue
		}
		selected = append(selected, v)
	}
	if filter != "" && len(selected) == 0 {
		return nil, fmt.Errorf("no vault for browser %q in keys (have: %s)", filter, vaultKeys(dump))
	}

	if !dirExists(dataDir) {
		return nil, fmt.Errorf("data dir %q does not exist", dataDir)
	}

	archiveLayout := isArchiveLayout(dataDir, selected)
	if !archiveLayout && len(selected) > 1 {
		return nil, fmt.Errorf("--data-dir %q has no per-browser subdir but keys has %d browsers; "+
			"point it at the archive root, or use -b <browser> for one browser's User Data (have: %s)",
			dataDir, len(selected), vaultKeys(dump))
	}

	var browsers []Browser
	for _, v := range selected {
		root := dataDir
		if archiveLayout {
			root = filepath.Join(dataDir, strings.ToLower(v.Browser))
			if !dirExists(root) {
				log.Warnf("restore: %s has no data under %s, skipping", v.Browser, root)
				continue
			}
		}
		kind, err := kindFromDump(v.Kind)
		if err != nil {
			log.Warnf("restore: %s: %v", v.Browser, err)
			continue

View on GitHub (pinned to 0503d04d7a)

Solutions

  1. Add -b <browser> to select the single browser whose User Data the dir directly contains
  2. Repoint --data-dir at the archive root that contains one subdirectory per browser so vaults can be matched by subdirectory
  3. Restructure the copied tree into per-browser subdirectories matching the browsers listed in the keys dump
  4. Regenerate the keys dump with only one browser if the others are irrelevant
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at browser/keydump.go:91 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of moonD4rk/HackBrowserData@0503d04d7a (2026-09-06). Data as JSON: /api/errors/f33b17202158ea9f. Report an issue: GitHub.