{"record":{"id":"b2f0e9778267158c","repo":"larksuite/cli","slug":"keychain-access-blocked","errorCode":null,"errorMessage":"keychain access blocked","messagePattern":"keychain access blocked","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/keychain/keychain_darwin.go","lineNumber":50,"sourceCode":"const ivBytes = 12\n\n// tagBytes is the authentication tag size produced by AES-GCM.\nconst tagBytes = 16\n\n// fileMasterKeyName is the local fallback master key file name.\nconst fileMasterKeyName = \"master.key.file\"\n\n// keyringGet is overridden in tests to simulate system keychain reads.\nvar keyringGet = keyring.Get\n\n// keyringSet is overridden in tests to simulate system keychain writes.\nvar keyringSet = keyring.Set\n\n// errKeychainBlocked is returned when the OS Keychain is reachable but\n// denies access — sandbox restriction, user-denied prompt, or a 5-second\n// timeout (typically caused by an ignored permission dialog). Distinct\n// from errNotInitialized (master key entry genuinely absent).\nvar errKeychainBlocked = errors.New(\"keychain access blocked\")\n\n// StorageDir returns the storage directory for a given service name on macOS.\nfunc StorageDir(service string) string {\n\thome, err := vfs.UserHomeDir()\n\tif err != nil || home == \"\" {\n\t\treturn filepath.Join(\".lark-cli\", \"keychain\", service)\n\t}\n\treturn filepath.Join(home, \"Library\", \"Application Support\", service)\n}\n\nvar safeFileNameRe = regexp.MustCompile(`[^a-zA-Z0-9._-]`)\n\n// safeFileName sanitizes an account name to be used as a safe file name.\nfunc safeFileName(account string) string {\n\treturn safeFileNameRe.ReplaceAllString(account, \"_\") + \".enc\"\n}\n\n// getMasterKey retrieves the master key from the system keychain.","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/keychain/keychain_darwin.go#L32-L68","documentation":"errKeychainBlocked is returned when the OS keychain is reachable but denies access — a sandbox restriction, a user-denied permission prompt, or the 5-second getMasterKey timeout caused by an ignored permission dialog. It is deliberately distinct from errNotInitialized (entry genuinely absent) so wrapError's hint can tell users the difference and suggest permission fixes rather than reconfiguration.","triggerScenarios":"Calling keychain operations on macOS where the security prompt is denied or ignored (ctx timeout at keychain_darwin.go:126), or keyring.Get returns an error other than ErrNotFound (keychain_darwin.go:94).","commonSituations":"Running lark-cli inside an IDE terminal or CI sandbox without keychain entitlements; the macOS 'allow access' dialog appearing off-screen or behind other windows and timing out; corporate MDM policies blocking keychain access.","solutions":["Re-run the command and click 'Always Allow' on the macOS keychain permission dialog","Run the CLI outside the sandbox/IDE sandbox (grant the host app keychain access in System Settings)","If in CI, pre-unlock the keychain / grant the runner access, or configure a non-keychain storage path"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// probe keychain access early with a cheap Get on a known service\nif _, err := kc.Get(service, account); err != nil && errors.Is(err, errKeychainBlocked) {\n    // surface permission guidance before the real operation\n}","typeGuard":"func isKeychainBlocked(err error) bool { return errors.Is(err, errKeychainBlocked) }","tryCatchPattern":"err := kc.Set(service, account, secret)\nif errors.Is(err, errKeychainBlocked) {\n    // retry once after user grants keychain access, else print the sandbox/permission hint\n}","preventionTips":["Answer 'Always Allow' on macOS keychain prompts promptly (5s timeout)","Avoid running the CLI inside hardened IDE sandboxes; use a regular terminal","Pre-provision keychain entitlements for CI runners","Keep dialogs visible — ignored prompts surface as errKeychainBlocked via timeout"],"tags":["keychain","macos","permissions"],"backgroundTag":"keychain-access-denied","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}