larksuite/cli · info

keychain: item not found

Error message

keychain: item not found

What it means

keychain.ErrNotFound is returned when the requested credential (service+account entry) does not exist in the OS keychain/credential store. Get surfaces it and wrapError passes it through unchanged (it is terminal, not a hint case). Callers like the config loader treat it as 'no stored credential' — an expected, recoverable state — rather than a failure of the keychain itself.

Source

Thrown at internal/keychain/keychain.go:17

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT

// Package keychain provides cross-platform secure storage for secrets.
// macOS uses the system Keychain; Linux uses AES-256-GCM encrypted files; Windows uses DPAPI + registry.
package keychain

import (
	"errors"
	"fmt"

	"github.com/larksuite/cli/errs"
)

var (
	// ErrNotFound is returned when the requested credential is not found.
	ErrNotFound = errors.New("keychain: item not found")

	// errNotInitialized is an internal error indicating the master key is missing or invalid.
	errNotInitialized = errors.New("keychain not initialized")
)

const (
	// LarkCliService is the unified keychain service name for all secrets.
	// Entries are distinguished by account key format:
	//   - AppSecret: "appsecret:<appId>"
	//   - Stored TAT: "tat:v1:<sha256(appId)>"
	//   - UAT:       "<appId>:<userOpenId>"
	LarkCliService = "lark-cli"
)

// wrapError wraps underlying keychain failures into a typed *errs.APIError
// (exit code 1) carrying a hint for troubleshooting keychain access issues.
// nil and ErrNotFound pass through unchanged.
func wrapError(op string, err error) error {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Run `lark-cli config init` (or the relevant auth flow) to store the credential
  2. Check you are running as the same OS user that stored the credential
  3. Handle ErrNotFound explicitly in code as 'not configured' rather than a hard failure

Example fix

// before
secret, err := kc.Get(service, account)
if err != nil { return err }
// after
secret, err := kc.Get(service, account)
if errors.Is(err, keychain.ErrNotFound) { return nil // prompt user to configure }
Defensive patterns

Strategy: type-guard

Validate before calling

// check config state before touching the keychain
if _, err := kc.Get(service, account); errors.Is(err, keychain.ErrNotFound) {
    // credential absent — run `lark-cli config init`
}

Type guard

func isCredentialMissing(err error) bool { return errors.Is(err, keychain.ErrNotFound) }

Try / catch

secret, err := kc.Get(service, account)
switch {
case errors.Is(err, keychain.ErrNotFound):
    // prompt user to configure; not a keychain failure
case err != nil:
    // real keychain failure
}

Prevention

When it happens

Trigger: Calling keychain Get for a service/account (e.g. appsecret:<appId>) that was never Set, or after the entry was deleted; stubbing in tests (config_test.go stubKeychain returns it).

Common situations: Fresh machine or fresh user profile with no stored credentials; running `config init` never executed; credential removed by keychain cleanup or a different user account.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/4a0484f8d2cc349c. Report an issue: GitHub.