Skip to content

run-gemini-cli fails with Cloud Code Private API error when using Code Assist and WIF #258

@grhoades

Description

@grhoades

TL;DR

Overview

When attempting to use the run-gemini-cli action with use_gemini_code_assist: true and authenticating via Workload Identity Federation, the action fails during the gemini-cli execution. The error message indicates that the "Cloud Code Private API" is not enabled, even though all required public APIs and IAM permissions appear to be correctly configured.

Workflow Configuration

Here is the relevant step from our workflow file. Project-specific identifiers have been replaced with placeholders.

- name: 'Run Gemini issue analysis'
  id: 'gemini_analysis'
  uses: 'google-github-actions/run-gemini-cli@v0'
  with:
    gcp_workload_identity_provider: 'projects/[PROJECT_NUMBER]/locations/global/workloadIdentityPools/[POOL_ID]/providers/[PROVIDER_ID]'
    gcp_project_id: '[YOUR_GCP_PROJECT_ID]'
    gcp_location: 'us-central1'
    gcp_service_account: '[YOUR_SERVICE_ACCOUNT_EMAIL]'
    use_gemini_code_assist: true
    settings: |
      {
        "maxSessionTurns": 25,
        "telemetry": { "enabled": true, "target": "gcp" },
        "coreTools": [ "run_shell_command(echo)" ]
      }
    prompt: |
      ## Role
      You are an issue triage assistant...

Expected behavior

Workflows run correctly and utilize the Google Cloud Code Assist Enterprise subscription.

Observed behavior

Error Log

The workflow fails with the following error. The project number in the URL has been redacted.

##[error]An unexpected critical error occurred:
An unexpected critical error occurred:
Error: Cloud Code Private API has not been used in project [YOUR_PROJECT_NUMBER] before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudcode-pa.googleapis.com/overview?project=[YOUR_PROJECT_NUMBER] then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
    at Gaxios._request (/usr/local/lib/node_modules/@google/gemini-cli/node_modules/gaxios/build/src/gaxios.js:142:23)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    # ... stack trace continues

Troubleshooting Steps Performed

We have already attempted the following steps without success:

  • Corrected Workflow Inputs: Removed all invalid parameters (google_api_key, gemini_debug, gemini_model) from the with: block.
  • Set Specific GCP Location: Changed gcp_location from global to us-central1.
  • Verified CLI Version: The workflow is using gemini-cli version 0.2.2, which appears to be the latest version available on npm.
  • Verified API Enablement: Confirmed that the Gemini for Google Cloud API (cloudaicompanion.googleapis.com) is enabled for the project.
  • Verified IAM Roles: Confirmed the service account has both the Gemini for Google Cloud User and Service Usage Consumer roles.

Despite these steps, the error persists, suggesting a potential bug in how the CLI resolves the Code Assist endpoint when using Workload Identity Federation.

Action YAML

name: '🔀 Gemini Triage'

on:
  workflow_call:
    inputs:
      additional_context:
        type: 'string'
        description: 'Any additional context from the request'
        required: false

concurrency:
  group: '${{ github.workflow }}-triage-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number }}'
  cancel-in-progress: true

defaults:
  run:
    shell: 'bash'

jobs:
  triage:
    runs-on: 'ubuntu-latest'
    timeout-minutes: 7
    outputs:
      available_labels: '${{ steps.get_labels.outputs.available_labels }}'
      selected_labels: '${{ env.SELECTED_LABELS }}'
    permissions:
      contents: 'read'
      id-token: 'write'
      issues: 'read'
      pull-requests: 'read'
    steps:
      - name: 'Get repository labels'
        id: 'get_labels'
        uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea' # ratchet:actions/github-script@v7.0.1
        with:
          # NOTE: we intentionally do not use the given token. The default
          # GITHUB_TOKEN provided by the action has enough permissions to read
          # the labels.
          script: |-
            const { data: labels } = await github.rest.issues.listLabelsForRepo({
              owner: context.repo.owner,
              repo: context.repo.repo,
            });

            if (!labels || labels.length === 0) {
              core.setFailed('There are no issue labels in this repository.')
            }

            const labelNames = labels.map(label => label.name).sort();
            core.setOutput('available_labels', labelNames.join(','));
            core.info(`Found ${labelNames.length} labels: ${labelNames.join(', ')}`);
            return labelNames;

      - name: 'Run Gemini issue analysis'
        id: 'gemini_analysis'
        if: |-
          ${{ steps.get_labels.outputs.available_labels != '' }}
        uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
        env:
          GITHUB_TOKEN: '' # Do NOT pass any auth tokens here since this runs on untrusted inputs
          ISSUE_TITLE: '${{ github.event.issue.title }}'
          ISSUE_BODY: '${{ github.event.issue.body }}'
          AVAILABLE_LABELS: '${{ steps.get_labels.outputs.available_labels }}'
        with:
          gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
          gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
          gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
          gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
          gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
          use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
          use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
          settings: |-
            {
              "maxSessionTurns": 25,
              "telemetry": {
                "enabled": ${{ vars.GOOGLE_CLOUD_PROJECT != '' }},
                "target": "gcp"
              },
              "coreTools": [
                "run_shell_command(echo)"
              ]
            }
          # For reasons beyond my understanding, Gemini CLI cannot set the
          # GitHub Outputs, but it CAN set the GitHub Env.
          prompt: |-
            ## Role

            You are an issue triage assistant. Analyze the current GitHub issue and identify the most appropriate existing labels. Use the available tools to gather information; do not ask for information to be provided.

            ## Guidelines

            - Retrieve the value for environment variables using the "echo" shell command.
            - Environment variables are specified in the format "${VARIABLE}" (with quotes and braces).
            - Only use labels that are from the list of available labels.
            - You can choose multiple labels to apply.

            ## Steps

            1. Retrieve the available labels from the environment variable: "${AVAILABLE_LABELS}".

            2. Retrieve the issue title from the environment variable: "${ISSUE_TITLE}".

            3. Retrieve the issue body from the environment variable: "${ISSUE_BODY}".

            4. Review the issue title, issue body, and available labels.

            5. Based on the issue title and issue body, classify the issue and choose all appropriate labels from the list of available labels.

            5. Classify the issue by identifying the appropriate labels from the list of available labels.

            6. Convert the list of appropriate labels into a comma-separated list (CSV). If there are no appropriate labels, use the empty string.

            7. Use the "echo" shell command to append the CSV labels into the filepath referenced by the environment variable "${GITHUB_ENV}":

                
                echo "SELECTED_LABELS=[APPROPRIATE_LABELS_AS_CSV]" >> "[filepath_for_env]"
                

                for example:

                
                echo "SELECTED_LABELS=bug,enhancement" >> "/tmp/runner/env"
                

  label:
    runs-on: 'ubuntu-latest'
    needs:
      - 'triage'
    if: |-
      ${{ needs.triage.outputs.selected_labels != '' }}
    permissions:
      contents: 'read'
      issues: 'write'
      pull-requests: 'write'
    steps:
      - name: 'Mint identity token'
        id: 'mint_identity_token'
        if: |-
          ${{ vars.APP_ID }}
        uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' # ratchet:actions/create-github-app-token@v2
        with:
          app-id: '${{ vars.APP_ID }}'
          private-key: '${{ secrets.APP_PRIVATE_KEY }}'
          permission-contents: 'read'
          permission-issues: 'write'
          permission-pull-requests: 'write'

      - name: 'Apply labels'
        env:
          ISSUE_NUMBER: '${{ github.event.issue.number }}'
          AVAILABLE_LABELS: '${{ needs.triage.outputs.available_labels }}'
          SELECTED_LABELS: '${{ needs.triage.outputs.selected_labels }}'
        uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea' # ratchet:actions/github-script@v7.0.1
        with:
          # Use the provided token so that the "gemini-cli" is the actor in the
          # log for what changed the labels.
          github-token: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
          script: |-
            // Parse the available labels
            const availableLabels = (process.env.AVAILABLE_LABELS || '').split(',')
              .map((label) => label.trim())
              .sort()

            // Parse the label as a CSV, reject invalid ones - we do this just
            // in case someone was able to prompt inject malicious labels.
            const selectedLabels = (process.env.SELECTED_LABELS || '').split(',')
              .map((label) => label.trim())
              .filter((label) => availableLabels.includes(label))
              .sort()

            // Set the labels
            const issueNumber = process.env.ISSUE_NUMBER;
            if (selectedLabels && selectedLabels.length > 0) {
              await github.rest.issues.setLabels({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: issueNumber,
                labels: selectedLabels,
              });
              core.info(`Successfully set labels: ${selectedLabels.join(',')}`);
            } else {
              core.info(`Failed to determine labels to set. There may not be enough information in the issue or pull request.`)
            }

Log output

2025-09-03T11:30:43.5749877Z ##[endgroup]
2025-09-03T11:30:45.3708641Z ##[error]An unexpected critical error occurred:
2025-09-03T11:30:45.3711396Z An unexpected critical error occurred:
2025-09-03T11:30:45.3715214Z Error: Cloud Code Private API has not been used in project 195846694092 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudcode-pa.googleapis.com/overview?project=195846694092 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
2025-09-03T11:30:45.3717260Z     at Gaxios._request (/usr/local/lib/node_modules/@google/gemini-cli/node_modules/gaxios/build/src/gaxios.js:142:23)
2025-09-03T11:30:45.3717906Z     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
2025-09-03T11:30:45.3718660Z     at async OAuth2Client.requestAsync (/usr/local/lib/node_modules/@google/gemini-cli/node_modules/google-auth-library/build/src/auth/oauth2client.js:429:18)
2025-09-03T11:30:45.3720192Z     at async CodeAssistServer.requestPost (file:///usr/local/lib/node_modules/@google/gemini-cli/node_modules/@google/gemini-cli-core/dist/src/code_assist/server.js:55:21)
2025-09-03T11:30:45.3721288Z     at async CodeAssistServer.loadCodeAssist (file:///usr/local/lib/node_modules/@google/gemini-cli/node_modules/@google/gemini-cli-core/dist/src/code_assist/server.js:39:16)
2025-09-03T11:30:45.3722264Z     at async setupUser (file:///usr/local/lib/node_modules/@google/gemini-cli/node_modules/@google/gemini-cli-core/dist/src/code_assist/setup.js:26:21)
2025-09-03T11:30:45.3723272Z     at async createCodeAssistContentGenerator (file:///usr/local/lib/node_modules/@google/gemini-cli/node_modules/@google/gemini-cli-core/dist/src/code_assist/codeAssist.js:14:26)
2025-09-03T11:30:45.3724352Z     at async createContentGenerator (file:///usr/local/lib/node_modules/@google/gemini-cli/node_modules/@google/gemini-cli-core/dist/src/core/contentGenerator.js:57:44)
2025-09-03T11:30:45.3725333Z     at async GeminiClient.initialize (file:///usr/local/lib/node_modules/@google/gemini-cli/node_modules/@google/gemini-cli-core/dist/src/core/client.js:86:33)
2025-09-03T11:30:45.3726289Z     at async Config.refreshAuth (file:///usr/local/lib/node_modules/@google/gemini-cli/node_modules/@google/gemini-cli-core/dist/src/config/config.js:258:9)
2025-09-03T11:30:45.3728352Z ##[error]Process completed with exit code 1.

Additional information

No response

Metadata

Metadata

Assignees

Labels

area/autharea/toolskind/bugSomething isn't workingpriority/p0Critical and urgent e.g., critical security vulnerability, major breakage

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions