n8n-io/n8n · error · Error

No credential template for type "${credentialType}" — add on

Error message

No credential template for type "${credentialType}" — add one to evaluations/credentials/seeder.ts

What it means

Thrown by `createOneCredential()` in credentials/seeder.ts when the requested `credentialType` has no entry in the `CREDENTIAL_TEMPLATES` record. The template record is the closed registry of credential types the eval harness knows how to seed (slackApi, notionApi, githubApi, gmailOAuth2, googleDriveOAuth2Api, linearMcpOAuth2Api, notionMcpOAuth2Api, microsoftTeamsOAuth2Api, whatsAppTriggerApi, googlePalmApi, httpHeaderAuth, httpBearerAuth, httpBasicAuth, openAiApi). The exported `SUPPORTED_CREDENTIAL_TYPES` Set is the authoritative list the case-file schema validates against, so a well-formed case should never reach this throw — it's a guard against drift between the schema and the seeder.

Source

Thrown at packages/@n8n/instance-ai/evaluations/credentials/seeder.ts:138

 * Create a single credential of the given type. Throws on an unknown type and
 * on creation failure — callers decide what a failure means for their flow
 * (declared-credential seeding fails the build; a mid-run "create" decision
 * falls back to decline, see `user-proxy/tools.ts`).
 *
 * `usedNames` de-dupes display names across calls that share it (e.g. every
 * declared credential in one `createDeclaredCredentials` batch) by appending
 * `#2`, `#3`, ... — pass a fresh `Map` for an unrelated, independent batch.
 */
export async function createOneCredential(
	client: N8nClient,
	credentialType: string,
	name: string | undefined,
	usedNames: Map<string, number>,
	options?: { logger?: EvalLogger },
): Promise<CreatedCredential> {
	const template = CREDENTIAL_TEMPLATES[credentialType];
	if (!template) {
		throw new Error(
			`No credential template for type "${credentialType}" — add one to evaluations/credentials/seeder.ts`,
		);
	}

	const base = name ?? template.defaultName;
	const count = (usedNames.get(base) ?? 0) + 1;
	usedNames.set(base, count);
	const resolvedName = count > 1 ? `${base} #${count}` : base;

	const envToken = template.envVar ? process.env[template.envVar] : undefined;
	const token = envToken ?? PLACEHOLDER_TOKEN;
	options?.logger?.verbose(`  Creating credential ${resolvedName} (${credentialType})`);
	// No retry: a credential POST isn't idempotent, so retrying after a lost response would orphan a duplicate we never capture for cleanup.
	const { id } = await client.createCredential(
		resolvedName,
		credentialType,
		template.buildData(token),
	);

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Open evaluations/credentials/seeder.ts and add a new entry to `CREDENTIAL_TEMPLATES` keyed by the exact type string from the error, with `defaultName`, optional `envVar`, and a `buildData(token)` that returns the credential's data shape.
  2. Confirm `SUPPORTED_CREDENTIAL_TYPES` (derived from the templates' keys) now includes the type — the case-file schema will pick it up automatically.
  3. If the type is a typo in the case JSON (e.g. `slackApiV2` vs `slackApi`), fix the JSON instead of adding a template.

Example fix

// before (seeder.ts)
const CREDENTIAL_TEMPLATES = {
  slackApi: { ... },
  // missing: airtableApi
};
// after
const CREDENTIAL_TEMPLATES = {
  slackApi: { ... },
  airtableApi: {
    defaultName: '[eval] Airtable',
    envVar: 'EVAL_AIRTABLE_API_KEY',
    buildData: (key) => ({ apiKey: key }),
  },
};
Defensive patterns

Strategy: type-guard

Validate before calling

import { SUPPORTED_CREDENTIAL_TYPES } from './seeder';
function isSupportedCredentialType(t: string): boolean {
  return SUPPORTED_CREDENTIAL_TYPES.has(t);
}
// before seeding
for (const c of declared) {
  if (!isSupportedCredentialType(c.type)) {
    throw new Error(`Unsupported credential type: ${c.type}`);
  }
}

Type guard

function isKnownCredentialType(type: string, known: ReadonlySet<string>): type is string {
  return known.has(type);
}

Prevention

When it happens

Trigger: A test case JSON declares a credential type the seeder hasn't been taught (e.g. a newly added n8n credential type used in a workflow before someone extends CREDENTIAL_TEMPLATES). The case-file schema check (`SUPPORTED_CREDENTIAL_TYPES`) was bypassed or drifted out of sync. A mid-run agent decision to create a credential (`UserProxyLlm`'s create-credential tool) named a type not in the registry.

Common situations: Adding a new integration to the eval suite: the workflow case file references a credential type, but no one added a template. Renaming a credential type in n8n core without updating both the schema allow-list and the templates map.

Related errors


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