plandex-ai/plandex · error

error reading accounts.json: %v

Error message

error reading accounts.json: %v

What it means

loadAccounts reads the CLI's accounts store at fs.HomeAccountsPath (~/.plandex/accounts.json). A missing file is handled gracefully (empty list), but any other read error — permission denied, path is a directory, I/O failure — is wrapped in this error and blocks sign-in and account storage.

Source

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

	"encoding/json"
	"fmt"
	"os"
	"plandex-cli/fs"

	shared "plandex-shared"
)

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)

View on GitHub (pinned to e2d772072e)

Solutions

  1. Check permissions on ~/.plandex/accounts.json (ls -la) and fix with chown/chmod
  2. If the path is a directory or corrupt symlink, remove/replace it
  3. Verify HOME is set correctly and points to a writable directory
  4. Check disk health / free space if I/O errors persist

Example fix

// before
$ sudo plandex-cli sign-in   # accounts.json now root-owned
error reading accounts.json: open ...: permission denied
// after
$ sudo chown -R $USER ~/.plandex
$ plandex-cli sign-in
Defensive patterns

Strategy: validation

Validate before calling

// check the accounts file is readable before auth flows
path := fs.HomeAccountsPath
if info, err := os.Stat(path); err == nil && info.IsDir() {
    return fmt.Errorf("%s is a directory; remove it", path)
}
f, err := os.OpenFile(path, os.O_RDONLY, 0)
if err != nil && !os.IsNotExist(err) {
    return fmt.Errorf("accounts.json unreadable: %v", err)
}
f.Close()

Type guard

func accountsReadable(path string) bool {
    f, err := os.Open(path)
    if err != nil {
        return os.IsNotExist(err)
    }
    f.Close()
    return true
}

Try / catch

accounts, err := loadAccounts()
if err != nil {
    if strings.Contains(err.Error(), "error reading accounts.json") {
        // check/fix ~/.plandex permissions, then retry
    }
    return err
}

Prevention

When it happens

Trigger: os.ReadFile(fs.HomeAccountsPath) fails with an error that is not os.IsNotExist — e.g. accounts.json exists but is unreadable due to permissions, or the path is a directory, or a disk I/O error occurs.

Common situations: ~/.plandex owned by root after running with sudo; accounts.json replaced by a directory or symlink to an unreadable location; read-only or failing filesystem; overly restrictive file mode from a prior run (os.ModePerm writes).

Related errors


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