{"record":{"id":"4013b4f09fb64d37","repo":"larksuite/cli","slug":"failed-to-read-secret-file-s-w-4013b4","errorCode":null,"errorMessage":"failed to read secret file %s: %w","messagePattern":"failed to read secret file (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/core/secret_resolve.go","lineNumber":30,"sourceCode":")\n\nconst secretKeyPrefix = \"appsecret:\"\n\nfunc secretAccountKey(appId string) string {\n\treturn secretKeyPrefix + appId\n}\n\n// ResolveSecretInput resolves a SecretInput to a plain string.\n// SecretRef objects are resolved by source (file / keychain).\nfunc ResolveSecretInput(s SecretInput, kc keychain.KeychainAccess) (string, error) {\n\tif s.Ref == nil {\n\t\treturn s.Plain, nil\n\t}\n\tswitch s.Ref.Source {\n\tcase \"file\":\n\t\tdata, err := vfs.ReadFile(s.Ref.ID)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to read secret file %s: %w\", s.Ref.ID, err)\n\t\t}\n\t\treturn strings.TrimSpace(string(data)), nil\n\tcase \"keychain\":\n\t\treturn kc.Get(keychain.LarkCliService, s.Ref.ID)\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unknown secret source: %s\", s.Ref.Source)\n\t}\n}\n\n// ForStorage determines how to store a secret in config.json.\n// - SecretRef → preserved as-is\n// - Plain text → stored in keychain, returns keychain SecretRef\n// Returns error if keychain is unavailable (no silent plaintext fallback).\nfunc ForStorage(appId string, input SecretInput, kc keychain.KeychainAccess) (SecretInput, error) {\n\tif !input.IsPlain() {\n\t\treturn input, nil // SecretRef → keep as-is\n\t}\n\tkey := secretAccountKey(appId)","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/core/secret_resolve.go#L12-L48","documentation":"ResolveSecretInput resolves a SecretInput to the actual secret value. When the secret is a file reference, it reads the file via vfs.ReadFile and wraps any read failure with this error, including the file path and the underlying cause (missing file, permission denied, etc.).","triggerScenarios":"Calling ResolveSecretInput (via authLogoutRun or ResolveConfigFromMulti) when the config appSecret is {\"source\":\"file\",\"id\":\"<path>\"} and the referenced file cannot be read: missing, renamed, wrong permissions, or an unreadable/invalid path.","commonSituations":"Secret file deleted by cleanup scripts or tmp reapers; config copied to another machine where the absolute path does not exist; permissions changed so the CLI user cannot read it; containers where the host path was never mounted.","solutions":["Verify the file exists at the exact path in the id field (cat the path) and fix the path in config.json if it moved.","Fix file permissions so the CLI user can read it (e.g. chmod 600 /path/to/secret).","Store the secret in the OS keychain by re-running the CLI's config/login flow, switching to a keychain reference.","As a temporary unblock, set the secret inline as a plain string, then move it back to a file reference."],"exampleFix":"// before (config.json)\n\"appSecret\": {\"source\": \"file\", \"id\": \"/tmp/secret.txt\"} // file deleted\n// after\n\"appSecret\": {\"source\": \"file\", \"id\": \"/home/me/.lark/appsecret\"} // file restored, chmod 600","handlingStrategy":"validation","validationCode":"if ref := cfg.AppSecret.Ref; ref != nil && ref.Source == \"file\" {\n\tif _, err := os.Stat(ref.ID); err != nil {\n\t\treturn fmt.Errorf(\"secret file %s unreadable: %w\", ref.ID, err)\n\t}\n}","typeGuard":null,"tryCatchPattern":"secret, err := core.ResolveSecretInput(input, kc)\nif err != nil {\n\tvar pe *fs.PathError\n\tif errors.As(err, &pe) {\n\t\treturn fmt.Errorf(\"fix or recreate secret file %s: %w\", pe.Path, err)\n\t}\n\treturn err\n}","preventionTips":["Store secret files in a stable location (e.g. ~/.lark/) outside tmp dirs that get cleaned.","Mount secret files explicitly in containers and verify the paths exist there.","Set restrictive permissions (chmod 600) and confirm readability as the user running the CLI.","After moving machines or users, re-check every file reference in config.json."],"tags":["filesystem","secret","config","file-not-found"],"backgroundTag":"secret-file-unreadable","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"}