plandex-ai/plandex · error

error unmarshalling accounts.json: %v

Error message

error unmarshalling accounts.json: %v

What it means

loadAccounts successfully read accounts.json but json.Unmarshal could not parse its contents into []*shared.ClientAccount. This means the local accounts store is malformed — corrupt, truncated, hand-edited, or written by an incompatible CLI version with a schema change.

Source

Thrown at app/cli/auth/state.go:30

var Current *shared.ClientAuth

func loadAccounts() ([]*shared.ClientAccount, error) {
	bytes, err := os.ReadFile(fs.HomeAccountsPath)

	if err != nil {
		if os.IsNotExist(err) {
			// no accounts
			return []*shared.ClientAccount{}, nil
		} else {
			return nil, fmt.Errorf("error reading accounts.json: %v", err)
		}
	}

	var accounts []*shared.ClientAccount
	err = json.Unmarshal(bytes, &accounts)

	if err != nil {
		return nil, fmt.Errorf("error unmarshalling accounts.json: %v", err)
	}

	return accounts, nil
}

func setAuth(auth *shared.ClientAuth) error {
	err := storeAccount(&auth.ClientAccount)

	if err != nil {
		return fmt.Errorf("error storing account: %v", err)
	}

	Current = auth

	err = writeCurrentAuth()

	if err != nil {
		return fmt.Errorf("error writing auth: %v", err)

View on GitHub (pinned to e2d772072e)

Solutions

  1. Inspect ~/.plandex/accounts.json and fix or remove the invalid JSON
  2. Back it up, then delete it — the CLI recreates it on next sign-in (you'll need to sign in again)
  3. Validate the JSON with a linter (jq . accounts.json) before restoring
  4. Ensure CLI version matches the file's schema; don't hand-edit the store

Example fix

// before
$ cat ~/.plandex/accounts.json
{"id": ...}          # object, not array
error unmarshalling accounts.json: json: cannot unmarshal object into Go value of type []*shared.ClientAccount
// after
$ mv ~/.plandex/accounts.json ~/.plandex/accounts.json.bak
$ plandex-cli sign-in   # recreates valid accounts.json
Defensive patterns

Strategy: validation

Validate before calling

// validate accounts.json parses before auth flows touch it
bytes, err := os.ReadFile(fs.HomeAccountsPath)
if err == nil {
    var accounts []*shared.ClientAccount
    if err := json.Unmarshal(bytes, &accounts); err != nil {
        return fmt.Errorf("accounts.json corrupt, back it up and re-sign-in: %v", err)
    }
}

Type guard

func validAccountsJSON(path string) bool {
    b, err := os.ReadFile(path)
    if err != nil { return false }
    var accounts []*shared.ClientAccount
    return json.Unmarshal(b, &accounts) == nil
}

Try / catch

accounts, err := loadAccounts()
if err != nil {
    if strings.Contains(err.Error(), "error unmarshalling accounts.json") {
        // back up the corrupt file, delete it, and re-authenticate
        os.Rename(fs.HomeAccountsPath, fs.HomeAccountsPath+".bak")
    }
    return err
}

Prevention

When it happens

Trigger: json.Unmarshal(bytes, &accounts) fails on the contents of fs.HomeAccountsPath: invalid JSON syntax, wrong top-level type (e.g. an object instead of an array), or fields that don't match shared.ClientAccount.

Common situations: File truncated by a crash or full disk mid-write; manual editing that broke JSON; downgrading/upgrading the CLI across a schema change; a stray non-JSON file placed at ~/.plandex/accounts.json.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/a6331efa1da301af. Report an issue: GitHub.