chenhg5/cc-connect · error
googlechat: read credentials_file: %w
Error message
googlechat: read credentials_file: %w
What it means
googlechat.New reads the service-account key file with os.ReadFile and wraps any OS-level failure as 'googlechat: read credentials_file: %w'. This fires after credentials_file is non-empty, so the path was provided but could not be read.
Source
Thrown at platform/googlechat/googlechat.go:101
func New(opts map[string]any) (core.Platform, error) {
subscription, _ := opts["subscription"].(string)
subscription = strings.TrimSpace(subscription)
if subscription == "" {
return nil, fmt.Errorf("googlechat: subscription is required (the Pub/Sub subscription your Chat app publishes to)")
}
projectID, err := projectFromSubscription(subscription)
if err != nil {
return nil, err
}
credentialsFile, _ := opts["credentials_file"].(string)
credentialsFile = strings.TrimSpace(credentialsFile)
if credentialsFile == "" {
return nil, fmt.Errorf("googlechat: credentials_file is required (the Chat app's service-account key, used to pull events and send replies)")
}
keyBytes, err := os.ReadFile(credentialsFile)
if err != nil {
return nil, fmt.Errorf("googlechat: read credentials_file: %w", err)
}
conf, err := google.JWTConfigFromJSON(keyBytes,
chatBotScope, "https://www.googleapis.com/auth/pubsub")
if err != nil {
return nil, fmt.Errorf("googlechat: parse service account credentials: %w", err)
}
botClient := conf.Client(context.Background())
allowFrom, _ := opts["allow_from"].(string)
core.CheckAllowFrom("googlechat", allowFrom)
return &Platform{
subscription: subscription,
projectID: projectID,
credentialsFile: credentialsFile,
tokenSource: conf.TokenSource(context.Background()),
allowFrom: allowFrom,View on GitHub (pinned to 4000b2338a)
Solutions
- Check the wrapped cause: 'no such file or directory' → fix the path; 'permission denied' → chmod/chown so the cc-connect process user can read the key
- Use an absolute path in credentials_file instead of a relative one
- Under systemd/daemon, confirm the key is mounted/available before the service starts and the WorkingDirectory is not misleading
- Verify with ls -l <path> as the same user the daemon runs as
Example fix
// before credentials_file = "sa.json" // after credentials_file = "/etc/cc-connect/sa.json" # absolute, readable by daemon user
Defensive patterns
Strategy: validation
Validate before calling
// Go: check readability before New
if info, err := os.Stat(path); err != nil {
return fmt.Errorf("credentials_file %q: %w", path, err)
} else if info.IsDir() {
return fmt.Errorf("credentials_file %q is a directory", path)
}
// and confirm the daemon user can read it Try / catch
p, err := core.CreatePlatform("googlechat", opts)
if err != nil && strings.Contains(err.Error(), "read credentials_file") {
return fmt.Errorf("check that the service-account key path is absolute and readable by the cc-connect user: %w", err)
} Prevention
- Use absolute paths for credentials_file
- Deploy keys via secret mounts that are ready before service start
- Set file ownership/permissions for the daemon user explicitly (chown cc-connect:cc-connect; chmod 600)
- Test `sudo -u cc-connect cat <keyfile>` after deployment
When it happens
Trigger: googlechat.New: os.ReadFile(credentialsFile) returns an error — file does not exist, permission denied on file or parent directories, path is a directory, or an I/O error — inside the platform constructor at startup.
Common situations: Typo in the path; relative path resolved against a different working directory when running under systemd; file mounted/secret not yet mounted at startup; restrictive file permissions after copying the key with umask 077 as a different user.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- googlechat: credentials_file is required (the Chat app's ser
- googlechat: subscription is required (the Pub/Sub subscripti
- googlechat: parse service account credentials: %w
- PreflightRunAsUser: RunAsUser is empty
- create Agy permission overlay: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/b5d890421b2ef97c.
Report an issue: GitHub.