decolua/9router · error

Vertex OAuth/ADC requires a project_id. Add…

Error message

Vertex OAuth/ADC requires a project_id. Add quota_project_id to your ADC JSON or set providerSpecificData.projectId.

What it means

Thrown by VertexExecutor.buildUrl (open-sse/executors/vertex.js:89) when Gemini on Vertex is requested with OAuth-style credentials (SA JSON, ADC authorized_user JSON, or a pre-set accessToken) but no project_id could be determined. OAuth flows must use the project-scoped path /projects/{id}/locations/{loc}/publishers/google/models/... to avoid Google's RESOURCE_PROJECT_INVALID error, so the executor fails fast with an actionable message instead.

Solutions

  1. Set providerSpecificData.projectId in the Vertex connection settings to your GCP project ID.
  2. For ADC credentials run `gcloud auth application-default set-quota-project YOUR_PROJECT_ID`, then re-save the ADC JSON so quota_project_id is present.
  3. Use a full Service Account JSON key (contains project_id) instead of a bare accessToken.
  4. If passing accessToken programmatically, also pass providerSpecificData: { projectId: '...' } in the same credentials object.

Example fix

// before
const creds = { accessToken: token };
// after
const creds = { accessToken: token, providerSpecificData: { projectId: "my-gcp-project", location: "us-central1" } };
Defensive patterns

Strategy: validation

Validate before calling

const sa = parseVertexSaJson(creds?.apiKey);
const adc = parseVertexAdcJson(creds?.apiKey);
const usesOAuth = !!sa || !!adc || !!creds?.accessToken;
const projectId = sa?.project_id || adc?.quota_project_id || creds?.providerSpecificData?.projectId;
if (usesOAuth && !projectId) {
  throw new Error("Vertex OAuth credentials need a project_id: set providerSpecificData.projectId or quota_project_id in the ADC JSON");
}

Type guard

function hasVertexOAuthProjectId(creds) {
  return Boolean(creds?.providerSpecificData?.projectId) || Boolean(parseVertexSaJson(creds?.apiKey)?.project_id) || Boolean(parseVertexAdcJson(creds?.apiKey)?.quota_project_id);
}

Try / catch

try {
  await chat(model, body);
} catch (e) {
  if (/Vertex OAuth\/ADC requires a project_id/.test(e.message)) {
    await configureVertexProject(connectionId);
  } else throw e;
}

Prevention

When it happens

Trigger: buildUrl is called with provider 'vertex', usesOAuth true (apiKey parsed as SA JSON, parsed as ADC authorized_user JSON, or credentials.accessToken already set), and all of saJson.project_id, adcJson.quota_project_id, and credentials.providerSpecificData.projectId are falsy.

Common situations: User pasted ADC credentials from `gcloud auth application-default login` on a machine where no quota project was configured; an accessToken was set manually (e.g. from `gcloud auth print-access-token`) without any projectId in providerSpecificData; a service-account JSON from an unusual source omitted project_id.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/551837bb96ed5d48. Report an issue: GitHub.

Appendix: source

Thrown at open-sse/executors/vertex.js:89

    const projectId =
      saJson?.project_id ||
      adcJson?.quota_project_id ||
      credentials?.providerSpecificData?.projectId;

    if (this.provider === "vertex-partner") {
      // Partner models require project_id in path regardless of auth method
      if (!projectId) throw new Error("Vertex partner models require a project_id. Add it in providerSpecificData or use Service Account JSON.");
      const url = `https://aiplatform.googleapis.com/v1/projects/${projectId}/locations/global/endpoints/openapi/chat/completions`;
      return rawKey ? `${url}?key=${rawKey}` : url;
    }

    // Gemini on Vertex
    const action = stream ? "streamGenerateContent" : "generateContent";

    if (usesOAuth) {
      // SA JSON / ADC / pre-set accessToken: must use project-scoped path to avoid RESOURCE_PROJECT_INVALID
      if (!projectId) {
        throw new Error(
          "Vertex OAuth/ADC requires a project_id. " +
          "Add quota_project_id to your ADC JSON or set providerSpecificData.projectId."
        );
      }
      const location = credentials?.providerSpecificData?.location || "us-central1";
      let url = `https://aiplatform.googleapis.com/v1/projects/${projectId}/locations/${location}/publishers/google/models/${model}:${action}`;
      if (stream) url += "?alt=sse";
      return url;
    }

    // Raw API key: use global publishers endpoint with ?key= param
    // ?alt=sse is required for proper SSE streaming (matches every other Gemini executor)
    let url = `https://aiplatform.googleapis.com/v1/publishers/google/models/${model}:${action}`;
    if (stream) url += "?alt=sse";
    if (rawKey) url += stream ? `&key=${rawKey}` : `?key=${rawKey}`;
    return url;
  }

View on GitHub (pinned to 90b52e06ff)