decolua/9router · error

Vertex partner models require a project_id. Add it in provid

Error message

Vertex partner models require a project_id. Add it in providerSpecificData or use Service Account JSON.

What it means

Thrown by VertexExecutor.buildUrl (open-sse/executors/vertex.js:78) when routing to the 'vertex-partner' provider (Llama, Mistral, GLM, DeepSeek, Qwen via Vertex AI's global OpenAI-compatible endpoint). The partner endpoint URL embeds the GCP project ID in the path (/projects/{id}/locations/global/endpoints/openapi/...), and unlike SA JSON or ADC credentials, a raw API key carries no project ID. The executor refuses to build a URL without one rather than sending a request that would fail upstream.

Source

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

 */
export class VertexExecutor extends BaseExecutor {
  constructor(providerId = "vertex") {
    super(providerId, PROVIDERS[providerId] || {});
  }

  buildUrl(model, stream, urlIndex = 0, credentials = null) {
    const saJson = parseVertexSaJson(credentials?.apiKey);
    const adcJson = parseVertexAdcJson(credentials?.apiKey);
    const usesOAuth = !!saJson || !!adcJson || !!credentials?.accessToken;
    const rawKey = !usesOAuth ? credentials?.apiKey : null;
    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";

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Open the Vertex partner provider's settings and set providerSpecificData.projectId to your GCP project ID (e.g. 'my-gcp-project').
  2. Switch the credential to a Service Account JSON key: download the key from GCP IAM (JSON type), ensure it contains project_id, and store it as the apiKey — buildUrl then reads saJson.project_id automatically.
  3. If using ADC JSON, set quota_project_id in it: run `gcloud auth application-default set-quota-project YOUR_PROJECT_ID` and re-paste the resulting JSON.
  4. Ensure execute() runs before buildUrl so the raw-key auto-resolution path (resolveProjectId probe) can fill projectId in; a bare buildUrl call with a raw key will always throw.

Example fix

// before (credential JSON)
{ "apiKey": "AQ.Ab8R..." }
// after
{ "apiKey": "AQ.Ab8R...", "providerSpecificData": { "projectId": "my-gcp-project" } }
Defensive patterns

Strategy: validation

Validate before calling

const sa = parseVertexSaJson(creds?.apiKey);
const adc = parseVertexAdcJson(creds?.apiKey);
const projectId = sa?.project_id || adc?.quota_project_id || creds?.providerSpecificData?.projectId;
if (provider === "vertex-partner" && !projectId) {
  throw new Error("Set providerSpecificData.projectId (or use SA JSON) before calling Vertex partner models");
}

Type guard

function hasVertexProjectId(creds) {
  const p = creds?.providerSpecificData?.projectId;
  return typeof p === "string" && p.trim().length > 0;
}

Try / catch

try {
  await route(request);
} catch (e) {
  if (/Vertex partner models require a project_id/.test(e.message)) {
    promptUserToSetProjectId();
  } else throw e;
}

Prevention

When it happens

Trigger: Calling buildUrl (directly or via execute) with provider 'vertex-partner' when projectId resolves to falsy: the apiKey is a raw key (not SA JSON parsed by parseVertexSaJson, not ADC parsed by parseVertexAdcJson), credentials.accessToken is unset, adcJson has no quota_project_id, saJson has no project_id, and credentials.providerSpecificData.projectId is missing/empty. Note: at runtime execute() tries to auto-resolve the project first — this throw from buildUrl alone happens when resolution was skipped or yielded nothing and projectId was never set.

Common situations: User pasted a Vertex express-mode API key into a partner-model connection without filling the projectId field in provider settings; ADC JSON was created by 'gcloud auth application-default login' before a quota project was set (gcloud auth application-default set-quota-project never run); SA JSON downloaded from a service account whose JSON lacks the project_id field; providerSpecificData was reset when the credential was re-imported.

Related errors


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