{"record":{"id":"94c7863bf24d6a9f","repo":"danny-avila/LibreChat","slug":"missing-azure-ai-search-service-endpoint-azure-ai","errorCode":null,"errorMessage":"Missing AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, or AZURE_AI_SEARCH_API_KEY environment variable.","messagePattern":"Missing AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, or AZURE_AI_SEARCH_API_KEY environment variable\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"api/app/clients/tools/structured/AzureAISearch.js","lineNumber":73,"sourceCode":"    );\n    this.queryType = this._initializeField(\n      fields.AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE,\n      'AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE',\n      AzureAISearch.DEFAULT_QUERY_TYPE,\n    );\n    this.top = this._initializeField(\n      fields.AZURE_AI_SEARCH_SEARCH_OPTION_TOP,\n      'AZURE_AI_SEARCH_SEARCH_OPTION_TOP',\n      AzureAISearch.DEFAULT_TOP,\n    );\n    this.select = this._initializeField(\n      fields.AZURE_AI_SEARCH_SEARCH_OPTION_SELECT,\n      'AZURE_AI_SEARCH_SEARCH_OPTION_SELECT',\n    );\n\n    // Check for required fields\n    if (!this.override && (!this.serviceEndpoint || !this.indexName || !this.apiKey)) {\n      throw new Error(\n        'Missing AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, or AZURE_AI_SEARCH_API_KEY environment variable.',\n      );\n    }\n\n    if (this.override) {\n      return;\n    }\n\n    // Create SearchClient\n    this.client = new SearchClient(\n      this.serviceEndpoint,\n      this.indexName,\n      new AzureKeyCredential(this.apiKey),\n      { apiVersion: this.apiVersion },\n    );\n  }\n\n  // Improved error handling and logging","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/app/clients/tools/structured/AzureAISearch.js#L55-L91","documentation":"Thrown by the AzureAISearch tool constructor when, after resolving each value via _initializeField (field arg → process.env → default), at least one of serviceEndpoint, indexName, or apiKey is still empty. The override flag exists specifically to let the app bootstrap and register the tool manifest without these vars. When override is false the constructor hard-fails, because it immediately proceeds to instantiate an @azure/search-documents SearchClient with those values.","triggerScenarios":"Constructing `new AzureAISearch({...})` (or any code path that loads structured tools, e.g. tool manifest initialization at startup) where AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, or AZURE_AI_SEARCH_API_KEY is unset in both the fields argument and process.env, and `fields.override` is not true.","commonSituations":"Fresh deployment or local dev where the .env file was copied from .env.example but the Azure AI Search keys were never filled in; CI runs missing the secret env vars; a docker container started without the env passthrough; refactoring that renamed the env vars; running tests that instantiate the real tool instead of stubbing it.","solutions":["Set the three env vars in your environment/.env: AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, AZURE_AI_SEARCH_API_KEY (verify with `printenv | grep AZURE_AI_SEARCH`).","If you are only initializing the tool registry/manifest (no actual search call), pass `override: true` in the fields object so the constructor skips the check and the SearchClient creation.","If you mean to use the tool, pass the values explicitly via the constructor fields object (keys: AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, AZURE_AI_SEARCH_API_KEY) so it does not depend on env.","Confirm there is no trailing typo in the env var names — _initializeField reads process.env[envVar] verbatim and is case-sensitive."],"exampleFix":"// before\nconst tool = new AzureAISearch({}); // throws if env vars unset\n\n// after (app bootstrap / manifest load)\nconst tool = new AzureAISearch({ override: true });\n\n// after (real usage)\nconst tool = new AzureAISearch({\n  AZURE_AI_SEARCH_SERVICE_ENDPOINT: endpoint,\n  AZURE_AI_SEARCH_INDEX_NAME: index,\n  AZURE_AI_SEARCH_API_KEY: key,\n});","handlingStrategy":"validation","validationCode":"function assertAzureAISearchConfig(fields = {}) {\n  const env = process.env;\n  const endpoint = fields.AZURE_AI_SEARCH_SERVICE_ENDPOINT || env.AZURE_AI_SEARCH_SERVICE_ENDPOINT;\n  const index = fields.AZURE_AI_SEARCH_INDEX_NAME || env.AZURE_AI_SEARCH_INDEX_NAME;\n  const key = fields.AZURE_AI_SEARCH_API_KEY || env.AZURE_AI_SEARCH_API_KEY;\n  const missing = [!endpoint && 'endpoint', !index && 'index', !key && 'apiKey'].filter(Boolean);\n  if (missing.length && !fields.override) {\n    throw new Error('AzureAISearch config missing: ' + missing.join(', '));\n  }\n}\n// call before: assertAzureAISearchConfig(fields); new AzureAISearch(fields);","typeGuard":"function hasAzureAISearchConfig(fields) {\n  const env = process.env;\n  return Boolean(\n    (fields.AZURE_AI_SEARCH_SERVICE_ENDPOINT || env.AZURE_AI_SEARCH_SERVICE_ENDPOINT) &&\n      (fields.AZURE_AI_SEARCH_INDEX_NAME || env.AZURE_AI_SEARCH_INDEX_NAME) &&\n      (fields.AZURE_AI_SEARCH_API_KEY || env.AZURE_AI_SEARCH_API_KEY),\n  );\n}","tryCatchPattern":null,"preventionTips":["Centralize required-env validation at process startup so missing Azure Search config fails fast with one clear message.","Always pass `override: true` when constructing the tool only to populate the manifest.","Keep Azure Search secrets in a managed secret store rather than ad-hoc .env edits."],"tags":["azure-ai-search","config","environment-variables","constructor"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}