{"record":{"id":"aa39ea1eed282f25","repo":"decolua/9router","slug":"vertex-partner-models-require-a-project-id-add-it","errorCode":null,"errorMessage":"Vertex partner models require a project_id. Add it in providerSpecificData or use Service Account JSON.","messagePattern":"Vertex partner models require a project_id\\. Add it in providerSpecificData or use Service Account JSON\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"open-sse/executors/vertex.js","lineNumber":78,"sourceCode":" */\nexport class VertexExecutor extends BaseExecutor {\n  constructor(providerId = \"vertex\") {\n    super(providerId, PROVIDERS[providerId] || {});\n  }\n\n  buildUrl(model, stream, urlIndex = 0, credentials = null) {\n    const saJson = parseVertexSaJson(credentials?.apiKey);\n    const adcJson = parseVertexAdcJson(credentials?.apiKey);\n    const usesOAuth = !!saJson || !!adcJson || !!credentials?.accessToken;\n    const rawKey = !usesOAuth ? credentials?.apiKey : null;\n    const projectId =\n      saJson?.project_id ||\n      adcJson?.quota_project_id ||\n      credentials?.providerSpecificData?.projectId;\n\n    if (this.provider === \"vertex-partner\") {\n      // Partner models require project_id in path regardless of auth method\n      if (!projectId) throw new Error(\"Vertex partner models require a project_id. Add it in providerSpecificData or use Service Account JSON.\");\n      const url = `https://aiplatform.googleapis.com/v1/projects/${projectId}/locations/global/endpoints/openapi/chat/completions`;\n      return rawKey ? `${url}?key=${rawKey}` : url;\n    }\n\n    // Gemini on Vertex\n    const action = stream ? \"streamGenerateContent\" : \"generateContent\";\n\n    if (usesOAuth) {\n      // SA JSON / ADC / pre-set accessToken: must use project-scoped path to avoid RESOURCE_PROJECT_INVALID\n      if (!projectId) {\n        throw new Error(\n          \"Vertex OAuth/ADC requires a project_id. \" +\n          \"Add quota_project_id to your ADC JSON or set providerSpecificData.projectId.\"\n        );\n      }\n      const location = credentials?.providerSpecificData?.location || \"us-central1\";\n      let url = `https://aiplatform.googleapis.com/v1/projects/${projectId}/locations/${location}/publishers/google/models/${model}:${action}`;\n      if (stream) url += \"?alt=sse\";","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/executors/vertex.js#L60-L96","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Open the Vertex partner provider's settings and set providerSpecificData.projectId to your GCP project ID (e.g. 'my-gcp-project').","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.","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.","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."],"exampleFix":"// before (credential JSON)\n{ \"apiKey\": \"AQ.Ab8R...\" }\n// after\n{ \"apiKey\": \"AQ.Ab8R...\", \"providerSpecificData\": { \"projectId\": \"my-gcp-project\" } }","handlingStrategy":"validation","validationCode":"const sa = parseVertexSaJson(creds?.apiKey);\nconst adc = parseVertexAdcJson(creds?.apiKey);\nconst projectId = sa?.project_id || adc?.quota_project_id || creds?.providerSpecificData?.projectId;\nif (provider === \"vertex-partner\" && !projectId) {\n  throw new Error(\"Set providerSpecificData.projectId (or use SA JSON) before calling Vertex partner models\");\n}","typeGuard":"function hasVertexProjectId(creds) {\n  const p = creds?.providerSpecificData?.projectId;\n  return typeof p === \"string\" && p.trim().length > 0;\n}","tryCatchPattern":"try {\n  await route(request);\n} catch (e) {\n  if (/Vertex partner models require a project_id/.test(e.message)) {\n    promptUserToSetProjectId();\n  } else throw e;\n}","preventionTips":["Always fill providerSpecificData.projectId when saving a Vertex partner connection with a raw API key.","Prefer Service Account JSON keys — they carry project_id natively.","Run `gcloud auth application-default set-quota-project` before copying ADC JSON.","Validate credentials at save time in the UI: warn if projectId is empty for vertex-partner."],"tags":["config","vertex-ai","missing-project-id","auth"],"backgroundTag":"missing-required-config-field","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}