fix(Microsoft SharePoint Trigger Node): Name the real cause in the missing-target error (no-changelog) (#40400)

This commit is contained in:
Stephen Wright 2026-10-12 12:44:08 +00:00 committed by GitHub
parent 6cd3539b1e
commit 27aa660a74
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 41 additions and 2 deletions

View File

@ -314,7 +314,7 @@ export class MicrosoftSharePointTrigger implements INodeType {
this.getNode(),
`The ${label} being watched is no longer reachable`,
{
description: `Microsoft Graph returned 404 for ${label} ${targetId} on site ${siteId}. It may have been deleted or renamed, or the credential may have lost access to it. The saved position is kept, so polling resumes if it comes back.`,
description: `Microsoft Graph returned 404 for ${label} ${targetId} on site ${siteId}. The ${label} was most likely deleted. ${watchingList ? 'A rename causes this only when the list is given by title rather than by ID.' : 'A rename does not cause this, because the node watches by ID.'} A credential that lost access returns a permission error instead. The saved position is kept, so polling resumes if the ${label} comes back.`,
},
)
: error;

View File

@ -1,5 +1,11 @@
import { readFileSync } from 'fs';
import type { IDataObject, INode, INodePropertyOptions, IPollFunctions } from 'n8n-workflow';
import type {
IDataObject,
INode,
INodePropertyOptions,
IPollFunctions,
NodeOperationError,
} from 'n8n-workflow';
import { join } from 'path';
import { mock } from 'vitest-mock-extended';
@ -21,6 +27,15 @@ vi.mock('../transport/delta', async (importOriginal) => ({
const deltaRequest = vi.mocked(microsoftApiRequestDelta);
const failureDescription = async (poll: () => Promise<unknown>) => {
try {
await poll();
} catch (error) {
return (error as NodeOperationError).description;
}
throw new Error('expected the poll to fail');
};
describe('Microsoft SharePoint Trigger', () => {
const { description } = new MicrosoftSharePointTrigger();
@ -357,6 +372,30 @@ describe('Microsoft SharePoint Trigger', () => {
await expect(poll()).rejects.toThrow('no longer reachable');
});
// A 404 means Graph could not find the ID. A rename keeps the ID, and a lost
// permission answers 403, so neither reaches this branch. Saying otherwise
// sends the reader to check the wrong thing.
it('blames deletion rather than a rename or a lost permission', async () => {
const { poll } = pollSetup({ mode: 'manual' });
deltaRequest.mockRejectedValue(Object.assign(new Error('Not Found'), { statusCode: 404 }));
const reason = await failureDescription(poll);
expect(reason).toContain('most likely deleted');
expect(reason).toContain('A rename does not cause this');
expect(reason).toContain('returns a permission error instead');
});
it('says a rename matters for a list given by title, and never for a library', async () => {
deltaRequest.mockRejectedValue(Object.assign(new Error('Not Found'), { statusCode: 404 }));
const list = await failureDescription(pollSetup({ mode: 'manual', resource: 'list' }).poll);
const library = await failureDescription(pollSetup({ mode: 'manual' }).poll);
expect(list).toContain('given by title');
expect(library).not.toContain('given by title');
});
it('goes quiet while one failure persists, rather than failing every poll', async () => {
const { ctx, state, poll } = pollSetup();
deltaRequest.mockRejectedValue(new Error('Service Unavailable'));