n8n-io/n8n · error · ForbiddenError

403

403

Error message

Forbidden

What it means

Thrown by the credential probe endpoint (POST against the persisted test URL) when credentialsService.probeById() raises CredentialNotFoundError. Same masking pattern as /test: the controller re-throws ForbiddenError() — its default message is the string 'Forbidden' (HTTP 403) — to avoid disclosing whether the credential is missing or merely forbidden.

Source

Thrown at packages/cli/src/credentials/credentials.controller.ts:184

	@ProjectScope('credential:read')
	async probeCredentials(
		req: AuthenticatedRequest,
		_res: unknown,
		@Param('credentialId') credentialId: string,
	) {
		try {
			const result = await this.credentialsService.probeById(req.user, credentialId);

			this.eventService.emit('credentials-probed', {
				user: req.user,
				credentialId,
				outcome: result.outcome,
			});

			return result;
		} catch (error) {
			if (error instanceof CredentialNotFoundError) {
				throw new ForbiddenError();
			}

			throw error;
		}
	}

	@Post('/')
	async createCredentials(
		req: AuthenticatedRequest,
		_: Response,
		@Body payload: CreateCredentialDto,
	) {
		const newCredential = await this.credentialsService.createUnmanagedCredential(
			payload,
			req.user,
		);

		const project = await this.sharedCredentialsRepository.findCredentialOwningProject(

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Verify the credential is owned/shared with the current user via GET /credentials before probing.
  2. Treat a 403 'Forbidden' from the probe endpoint as 'not accessible' and refresh the list.
  3. Ensure the user has credential:read on the owning project.
Defensive patterns

Strategy: validation

Validate before calling

async function canAccessCredential(credentialId: string) {
  const r = await fetch(`/rest/credentials/${credentialId}`);
  return r.ok;
}
if (!(await canAccessCredential(id))) {
  throw new Error('Credential not accessible; cannot probe');
}

Try / catch

try { await fetch(`/rest/credentials/${id}/probe`, { method: 'POST' }); }
catch (e) { if (e.statusCode === 403 && /forbidden/i.test(e.message)) { /* refresh list */ } else throw e; }

Prevention

When it happens

Trigger: Probing a credential whose id is unknown or not accessible to req.user; the service raises CredentialNotFoundError and the controller converts it to a generic 403 'Forbidden'.

Common situations: Generic credential types (e.g. Templated Custom Auth) being probed after the user lost access; id from another environment; credential deleted between selection and probe.

Understand the failure class

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/43f255c6c1a7cc40. Report an issue: GitHub.