From d7b98c5b0bb9dfdd9e785f2f3830aa7c2af4cde1 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 28 Jul 2026 16:37:39 -0700 Subject: [PATCH 1/2] fix(connectors): attribute SharePoint not-found errors to the matched library When the first path segment named a real non-default document library but the remainder did not resolve there, the failure message described a search of the default library over the full original path, and advised stripping a library prefix the user had supplied correctly. Report against the library that was matched, over the remainder that was actually searched, and only suggest omitting a leading library name when the default library really was the one searched. --- .../connectors/sharepoint/sharepoint.test.ts | 19 ++++++++++++ apps/sim/connectors/sharepoint/sharepoint.ts | 29 +++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/apps/sim/connectors/sharepoint/sharepoint.test.ts b/apps/sim/connectors/sharepoint/sharepoint.test.ts index 8a6fcc59e25..51153f1f93e 100644 --- a/apps/sim/connectors/sharepoint/sharepoint.test.ts +++ b/apps/sim/connectors/sharepoint/sharepoint.test.ts @@ -264,6 +264,25 @@ describe('resolveFolderTarget', () => { ) }) + it('blames the matched library, not the default one, when its remainder is wrong', async () => { + mockGraph({ + ...defaultDriveRoute, + ...sitesDrivesRoute, + ...rootChildren(DEFAULT_DRIVE_ID, [folder('d1', 'Archive')]), + ...rootChildren(POLICIES_DRIVE_ID, [folder('p1', 'Onboarding')]), + }) + + const error = await resolve('Policies/HR').catch((e: Error) => e) + + expect(error).toBeInstanceOf(Error) + const message = (error as Error).message + expect(message).toContain('document library "Policies"') + expect(message).toContain('"HR"') + expect(message).toContain('"Onboarding"') + expect(message).not.toContain('document library "Documents"') + expect(message).not.toContain('Shared Documents" should be omitted') + }) + it('surfaces a failure to open the default library rather than reporting not-found', async () => { mockGraph({ [`${GRAPH}/sites/${SITE_ID}/drive?$select=id,name,webUrl`]: { status: 403 }, diff --git a/apps/sim/connectors/sharepoint/sharepoint.ts b/apps/sim/connectors/sharepoint/sharepoint.ts index 875276eac60..e99d9fd51a9 100644 --- a/apps/sim/connectors/sharepoint/sharepoint.ts +++ b/apps/sim/connectors/sharepoint/sharepoint.ts @@ -527,14 +527,25 @@ export async function resolveFolderTarget( return { driveId: defaultDrive.id, driveName: defaultDriveName, folderId: walked.id } } + /** + * When the first segment named a real library, that library is the one the + * user meant — report against it and its remainder, not against the default + * library and the full path, which would blame the wrong library and advise + * stripping a prefix that was correct. + */ + const reportDrive = libraryMatch + ? { id: libraryMatch.id, name: libraryMatch.name || segments[0] } + : { id: defaultDrive.id, name: defaultDriveName } + throw new Error( await buildFolderNotFoundMessage( accessToken, - { id: defaultDrive.id, name: defaultDriveName }, + reportDrive, siteName || siteUrl, trimmed, - segments, + libraryMatch ? segments.slice(1) : segments, drives, + !libraryMatch, retryOptions ) ) @@ -572,6 +583,11 @@ function matchesDriveName(drive: Drive, segment: string): boolean { /** * Builds a diagnostic failure message naming the site, the library searched, * the path attempted, and the folders that actually exist at that level. + * + * `searchedDefaultLibrary` gates the advice about stripping a leading library + * name: that hint only applies when the path was interpreted against the site's + * default library, and would be actively misleading when the caller supplied a + * library name that matched. */ async function buildFolderNotFoundMessage( accessToken: string, @@ -580,6 +596,7 @@ async function buildFolderNotFoundMessage( rawFolderPath: string, segments: string[], drives: Drive[], + searchedDefaultLibrary: boolean, retryOptions?: RetryOptions ): Promise { const parts = [ @@ -614,9 +631,11 @@ async function buildFolderNotFoundMessage( } } - parts.push( - 'The folder path is relative to the document library root, so a leading "Documents" or "Shared Documents" should be omitted unless a folder by that name really exists.' - ) + if (searchedDefaultLibrary) { + parts.push( + 'The folder path is relative to the document library root, so a leading "Documents" or "Shared Documents" should be omitted unless a folder by that name really exists.' + ) + } return parts.join(' ') } From 01a136d07b342b81c973c2b8c92daea8713bc5f1 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 28 Jul 2026 16:43:26 -0700 Subject: [PATCH 2/2] fix(connectors): key the library-prefix hint on the library actually searched Deriving the flag from `!libraryMatch` suppressed the hint when the path named the default library itself ("Documents/Reports"), which is exactly the case the hint exists for. Key it on whether the reported drive is the default library. --- apps/sim/connectors/sharepoint/sharepoint.test.ts | 14 ++++++++++++++ apps/sim/connectors/sharepoint/sharepoint.ts | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/sim/connectors/sharepoint/sharepoint.test.ts b/apps/sim/connectors/sharepoint/sharepoint.test.ts index 51153f1f93e..ccb6165455d 100644 --- a/apps/sim/connectors/sharepoint/sharepoint.test.ts +++ b/apps/sim/connectors/sharepoint/sharepoint.test.ts @@ -283,6 +283,20 @@ describe('resolveFolderTarget', () => { expect(message).not.toContain('Shared Documents" should be omitted') }) + it('still offers the prefix hint when the path names the default library itself', async () => { + mockGraph({ + ...defaultDriveRoute, + ...sitesDrivesRoute, + ...rootChildren(DEFAULT_DRIVE_ID, [folder('d1', 'Archive')]), + }) + + const error = await resolve('Shared Documents/Reports').catch((e: Error) => e) + + const message = (error as Error).message + expect(message).toContain('document library "Documents"') + expect(message).toContain('Shared Documents" should be omitted') + }) + it('surfaces a failure to open the default library rather than reporting not-found', async () => { mockGraph({ [`${GRAPH}/sites/${SITE_ID}/drive?$select=id,name,webUrl`]: { status: 403 }, diff --git a/apps/sim/connectors/sharepoint/sharepoint.ts b/apps/sim/connectors/sharepoint/sharepoint.ts index e99d9fd51a9..f3d4b99bdf6 100644 --- a/apps/sim/connectors/sharepoint/sharepoint.ts +++ b/apps/sim/connectors/sharepoint/sharepoint.ts @@ -545,7 +545,7 @@ export async function resolveFolderTarget( trimmed, libraryMatch ? segments.slice(1) : segments, drives, - !libraryMatch, + reportDrive.id === defaultDrive.id, retryOptions ) )