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
- Run `lark-cli config init` (or the relevant auth flow) to store the credential
- Check you are running as the same OS user that stored the credential
- 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
- Run `lark-cli config init` on new machines/profiles
- Treat ErrNotFound as expected 'not configured' state in code
- Store credentials under the same OS user that consumes them
- Check keychain entries before deleting via system tools
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
- keychain not initialized
- keychain access blocked
- keychain unavailable: %w hint: use file: reference in config
- appSecret keychain key %q does not match appId %q (expected
- dpapi protect failed: %w
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/4a0484f8d2cc349c.
Report an issue: GitHub.