{"record":{"id":"fbf6761dc6b4124c","repo":"chenhg5/cc-connect","slug":"googlechat-parse-service-account-credentials-w","errorCode":null,"errorMessage":"googlechat: parse service account credentials: %w","messagePattern":"googlechat: parse service account credentials: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/googlechat/googlechat.go","lineNumber":106,"sourceCode":"\t}\n\tprojectID, err := projectFromSubscription(subscription)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcredentialsFile, _ := opts[\"credentials_file\"].(string)\n\tcredentialsFile = strings.TrimSpace(credentialsFile)\n\tif credentialsFile == \"\" {\n\t\treturn nil, fmt.Errorf(\"googlechat: credentials_file is required (the Chat app's service-account key, used to pull events and send replies)\")\n\t}\n\tkeyBytes, err := os.ReadFile(credentialsFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"googlechat: read credentials_file: %w\", err)\n\t}\n\tconf, err := google.JWTConfigFromJSON(keyBytes,\n\t\tchatBotScope, \"https://www.googleapis.com/auth/pubsub\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"googlechat: parse service account credentials: %w\", err)\n\t}\n\tbotClient := conf.Client(context.Background())\n\n\tallowFrom, _ := opts[\"allow_from\"].(string)\n\n\tcore.CheckAllowFrom(\"googlechat\", allowFrom)\n\n\treturn &Platform{\n\t\tsubscription:    subscription,\n\t\tprojectID:       projectID,\n\t\tcredentialsFile: credentialsFile,\n\t\ttokenSource:     conf.TokenSource(context.Background()),\n\t\tallowFrom:       allowFrom,\n\t\tsessionScope:    normalizeSessionScope(opts[\"session_scope\"]),\n\t\tbotClient:       botClient,\n\t}, nil\n}\n","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/googlechat/googlechat.go#L88-L124","documentation":"After reading the key file, googlechat.New parses it via google.JWTConfigFromJSON to build a JWT config with the Chat bot and Pub/Sub scopes. If the bytes are not a valid service-account JSON key, the parse fails and construction aborts with this wrapped error.","triggerScenarios":"googlechat.New: google.JWTConfigFromJSON(keyBytes, ...) errors because the file content is not a well-formed Google service-account JSON key — wrong file type, truncated download, OAuth client secret instead of a service-account key, or user credentials JSON.","commonSituations":"Downloading an OAuth client secret JSON instead of the service-account key; copying the key partially (truncated JSON); key file corrupted in transfer; accidentally pointing credentials_file at a config.toml or kubeconfig.","solutions":["Re-download a proper service-account JSON key from Google Cloud IAM (Service Accounts → Keys → Add key → JSON) and replace the file","Validate the file: it must be JSON containing fields like \"type\": \"service_account\", \"private_key\", \"client_email\" (jq . < file should parse)","Ensure you did not point credentials_file at an OAuth client secret or API key file","Check the file wasn't truncated (file size and closing brace) after copying through secret managers"],"exampleFix":"# verify the key is a service-account key before starting\njq -e '.type == \"service_account\"' /etc/cc-connect/chat-app-sa.json","handlingStrategy":"validation","validationCode":"// Go: sanity-check the key JSON before New\nraw, err := os.ReadFile(path)\nif err != nil { return err }\nvar probe map[string]any\nif err := json.Unmarshal(raw, &probe); err != nil {\n    return fmt.Errorf(\"credentials_file is not valid JSON: %w\", err)\n}\nif t, _ := probe[\"type\"].(string); t != \"service_account\" {\n    return fmt.Errorf(\"credentials_file type is %q, want service_account\", t)\n}","typeGuard":null,"tryCatchPattern":"p, err := core.CreatePlatform(\"googlechat\", opts)\nif err != nil && strings.Contains(err.Error(), \"parse service account credentials\") {\n    return fmt.Errorf(\"credentials_file must be a service-account JSON key, not an OAuth client secret or API key: %w\", err)\n}","preventionTips":["Download keys via IAM → Service Accounts → Keys (JSON), not the OAuth consent screen","Validate the JSON parses and has type=service_account in deployment scripts","Avoid manual copy/paste of key files which can truncate JSON","Version-control only the path, never the key, and re-download cleanly if corrupted"],"tags":["googlechat","service-account","jwt","credentials"],"backgroundTag":"invalid-config-value","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}