{"record":{"id":"ca8ac4810b4e1f0d","repo":"abhigyanpatwari/GitNexus","slug":"source-must-be-an-array-of-strings","errorCode":null,"errorMessage":"${source} must be an array of strings.","messagePattern":"(.+?) must be an array of strings\\.","errorType":"validation","errorClass":"GitNexusRcError","httpStatus":null,"severity":"warning","filePath":"gitnexus/src/cli/analyze-config.ts","lineNumber":246,"sourceCode":"      // inside `gitnexus://repo/${name}/…` code spans, so a Markdown-significant\n      // character would break those spans or inject emphasis/links/HTML into\n      // agent-instruction content (#1996 tri-review P1). `_` is intentionally\n      // allowed (legitimate in repo names; intraword `_` is not emphasis).\n      // embeddingDevice (the other `string`-kind option) only ever holds a\n      // fixed device token, so this guard never rejects a valid value there.\n      if (/[`*[\\]<>]/.test(trimmed)) {\n        throw new GitNexusRcError(\n          `${source} must not contain Markdown-significant characters (\\` * [ ] < >).`,\n        );\n      }\n      return trimmed;\n    }\n    case 'string-array': {\n      // Generic shared validator — `source` already names the config key, so\n      // messages here stay key-agnostic (no fetch-wrapper coupling in the\n      // shared normalizer; #1589/#1852 review F7).\n      if (!Array.isArray(value)) {\n        throw new GitNexusRcError(`${source} must be an array of strings.`);\n      }\n      const names: string[] = [];\n      for (const item of value) {\n        if (typeof item !== 'string') {\n          throw new GitNexusRcError(`${source} entries must all be strings.`);\n        }\n        const trimmed = item.trim();\n        if (!trimmed) {\n          throw new GitNexusRcError(`${source} entries must not be empty.`);\n        }\n        assertNoHiddenChars(trimmed, source);\n        // Values may be interpolated into a RegExp downstream. Restrict to\n        // identifier / member-access shapes so a config value can never smuggle\n        // regex metacharacters into a consumer.\n        if (!/^[A-Za-z_$][A-Za-z0-9_$.]*$/.test(trimmed)) {\n          throw new GitNexusRcError(\n            `${source} entry \"${trimmed}\" must be an identifier or member name ` +\n              `(letters, digits, _, $, . — e.g. \"client.get\").`,","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/cli/analyze-config.ts#L228-L264","documentation":"The wiki-generation LLM client detected an Azure endpoint (provider === 'azure' or an Azure-matching baseUrl) whose URL uses the legacy `/deployments/<name>/...` format, but no api-version is set. Azure requires the api-version query parameter on legacy deployment URLs; requests without it fail at the API. The client warns and proceeds — the fix is to add an API version or switch to the v1 URL format.","triggerScenarios":"isAzureProvider(config.baseUrl) is true and config.baseUrl.includes('/deployments/') while config.apiVersion is unset — e.g. baseUrl like https://<res>.openai.azure.com/deployments/<dep>/chat/completions with AZURE_API_VERSION (or --api-version) missing.","commonSituations":"Copying a legacy Azure OpenAI endpoint from older docs into wiki-generation config; migrating configs between v1 (`/openai/v1/...`) and legacy URL styles; API version env var dropped when moving from one environment to another.","solutions":["Pass the API version: --api-version 2024-10-21 (or the AZURE_API_VERSION env/config field)","Or switch baseUrl to the v1 API format, which does not need the per-request api-version","Verify the deployment name in the URL still exists in the Azure resource","Re-run wiki generation after setting it — the request itself would have been rejected without the parameter"],"exampleFix":"# before\nnpx gitnexus wiki --provider azure \\\n  --base-url https://myres.openai.azure.com/deployments/gpt-4o/chat/completions\n\n# after\nnpx gitnexus wiki --provider azure \\\n  --base-url https://myres.openai.azure.com/deployments/gpt-4o/chat/completions \\\n  --api-version 2024-10-21","handlingStrategy":"validation","validationCode":"// before building the client: normalize Azure config so the request cannot 400\nconst isLegacyAzureDeploymentsUrl = (baseUrl: string): boolean =>\n  /\\/deployments\\//.test(baseUrl);\nif (config.provider === 'azure' || isAzureProvider(config.baseUrl)) {\n  if (isLegacyAzureDeploymentsUrl(config.baseUrl) && !config.apiVersion) {\n    config = { ...config, apiVersion: config.apiVersion ?? '2024-10-21' };\n  }\n}","typeGuard":"const isAzureLegacyConfig = (c: LlmConfig): boolean =>\n  (c.provider === 'azure' || isAzureProvider(c.baseUrl)) &&\n  c.baseUrl.includes('/deployments/') &&\n  !c.apiVersion;","tryCatchPattern":null,"preventionTips":["Prefer the v1 API URL format for Azure endpoints","Always pair a legacy /deployments/ baseUrl with --api-version (or AZURE_API_VERSION)","Smoke-test wiki generation config with a 1-token request before long runs"],"tags":["azure","openai-compatible","api-version","llm-client"],"backgroundTag":"azure-api-version-missing","analyzedSha":"ac9a4e9abd8fd3058c070b72c23402a4f887929a","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}