{"record":{"id":"964e6d3b24a3eb10","repo":"Budibase/budibase","slug":"failed-to-fetch-sharepoint-sites-response-statu","errorCode":null,"errorMessage":"Failed to fetch SharePoint sites (${response.status})","messagePattern":"Failed to fetch SharePoint sites \\((.+?)\\)","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/ai/knowledgeSources/sharepoint/connection.ts","lineNumber":250,"sourceCode":"        // noop\n      }\n      console.error(\"Failed to fetch SharePoint sites (app token)\", {\n        status: response.status,\n        errorCode,\n        hasErrorDescription: !!errorDescription,\n      })\n      let errorMessage = `Failed to fetch SharePoint sites (${response.status})`\n      if (response.status === 401) {\n        errorMessage =\n          \"Authentication failed with Microsoft Graph. Verify SharePoint application credentials and try again.\"\n        throw new HTTPError(errorMessage, 401)\n      } else if (response.status === 403) {\n        errorMessage =\n          \"Access denied by Microsoft Graph. Ensure SharePoint application permissions are granted.\"\n      } else if (response.status === 400 && errorDescription) {\n        errorMessage = `Microsoft Graph rejected the SharePoint search request: ${errorDescription}`\n      }\n      throw new HTTPError(errorMessage, 400)\n    }\n    return (await response.json()) as {\n      value?: Array<{\n        id?: string\n        displayName?: string\n        name?: string\n        webUrl?: string\n      }>\n      \"@odata.nextLink\"?: string\n    }\n  }\n\n  for (let page = 0; nextLink && page < 50; page++) {\n    const payload = await fetchSitesPage(nextLink)\n    for (const site of payload.value || []) {\n      if (!site?.id) {\n        continue\n      }","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/ai/knowledgeSources/sharepoint/connection.ts#L232-L268","documentation":"Generic failure path of fetchSitesPage: any non-OK Graph response that is not 401 (and not a 403/400-with-description special case) becomes an HTTPError 400 with message 'Failed to fetch SharePoint sites (<status>)'. The original HTTP status is embedded in the message.","triggerScenarios":"Graph responds with a status like 429 (throttling), 500/503 (service unavailable), or a 403/400 without the specific payloads the special cases expect; also any unexpected status code.","commonSituations":"Graph API throttling under heavy site enumeration; transient Microsoft service outages; malformed search requests rejected with unusual codes; network proxies returning non-JSON bodies that defeat the error-description parsing.","solutions":["Read the HTTP status embedded in the message and retry later for 429/5xx (the request already goes through requestWithRetries).","For repeated failures, check the Microsoft Graph service health status page.","Inspect server logs — errorCode and description presence are logged before the throw.","Reduce page size ($top) or frequency of site fetches if throttled."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await fetchSharePointSitesByDatasourceAuthConfig(datasourceId, authConfigId)\n} catch (err) {\n  const status = Number(err?.message?.match(/\\((\\d+)\\)$/)?.[1])\n  if (status === 429 || status >= 500) {\n    // transient: back off and retry\n  }\n  throw err\n}","preventionTips":["Respect Graph throttling limits; reduce $top page size and call frequency.","Schedule large site enumerations off-peak.","Monitor Microsoft Graph service health for outages.","Rely on requestWithRetries for transient failures rather than adding ad-hoc retries."],"tags":["sharepoint","network","microsoft-graph","http-error"],"backgroundTag":"upstream-api-error","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}