n8n-io/n8n · error · InvalidRuntimeSkillError

Invalid skill at ${sourceDirectory}: ${formatSkillValidation

Error message

Invalid skill at ${sourceDirectory}: ${formatSkillValidationErrors(parsed.errors)}

What it means

Thrown by loadRuntimeSkillsFromDirectory while parsing each SKILL.md via parseRuntimeSkillMarkdown. It fires when the file's YAML frontmatter or body fails parsing — e.g. missing frontmatter delimiters, invalid YAML, an unknown field, a name that breaks the skill-name pattern, or a missing required 'name'/'description'. The error lists the source directory and every validation message via formatSkillValidationErrors. Wrapped as InvalidRuntimeSkillError.

Source

Thrown at packages/@n8n/agents/src/skills/registry.ts:142

	if (!existsSync(rootDir) || !statSync(rootDir).isDirectory()) return [];

	return collectSkillFiles(rootDir).map((skillPath) => {
		const skillDir = dirname(skillPath);
		const sourceDirectory = toPosixPath(relative(rootDir, skillDir));
		validateRuntimeSkillFolder(skillDir, skillPath, sourceDirectory);

		const content = readFileSync(skillPath, 'utf-8');
		const parsed = parseRuntimeSkillMarkdown(content, {
			sourceName: basename(skillDir),
			path: toPosixPath(skillPath),
			sourcePath: toPosixPath(skillPath),
			directory: toPosixPath(skillDir),
			sourceDirectory,
			category: categoryFor(sourceDirectory),
		});

		if (!parsed.ok) {
			throw new InvalidRuntimeSkillError(
				`Invalid skill at ${sourceDirectory}: ${formatSkillValidationErrors(parsed.errors)}`,
			);
		}

		return {
			...parsed.skill,
			linkedFiles: loadLinkedFiles(skillDir),
		};
	});
}

export function formatSkillValidationErrors(
	errors: Array<{ message: string; field?: string; path?: string; hint?: string }>,
): string {
	return errors
		.map((error) => {
			const field = error.field ? ` field "${error.field}"` : '';
			const path = error.path ? ` (${error.path})` : '';

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Open the SKILL.md at the source directory named in the message and start the file with a `---`-delimited YAML frontmatter block.
  2. Ensure frontmatter has required `name` (lowercase, matching /^[a-z0-9][a-z0-9._-]{0,63}$/) and `description` (non-empty string), plus a non-empty instruction body below the closing `---`.
  3. Remove or rename any unknown frontmatter keys; move extension data into the `metadata` object if you need it.
  4. Re-run; the error message enumerates each remaining problem field-by-field.

Example fix

# skills/billing/SKILL.md  (before)
---
Name: Billing
Descripton: Billing help
---

# skills/billing/SKILL.md  (after)
---
name: billing
description: Billing help
---
Instructions for the billing skill.
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from 'fs';
import { parseRuntimeSkillMarkdown } from '@n8n/agents/skills'; // or relative path

function prevalidateSkillFile(skillPath: string): void {
  const content = readFileSync(skillPath, 'utf-8');
  const result = parseRuntimeSkillMarkdown(content, { sourcePath: skillPath });
  if (!result.ok) {
    throw new Error(`Refusing to load ${skillPath}: ${JSON.stringify(result.errors)}`);
  }
}

Type guard

function hasValidFrontmatter(content: string): boolean {
  const lines = content.split(/\r?\n/);
  return lines[0]?.trim() === '---' && lines.slice(1).some((l, i) => i > 0 && l.trim() === '---');
}

if (!hasValidFrontmatter(readFileSync(skillPath, 'utf-8'))) {
  throw new Error(`${skillPath} missing --- delimited YAML frontmatter`);

Try / catch

import { InvalidRuntimeSkillError } from '@n8n/agents/skills';

try {
  loadRuntimeSkillSourceFromDirectory(rootDir);
} catch (err) {
  if (err instanceof InvalidRuntimeSkillError) {
    // parse error — log and skip / fail the build, do not retry
    console.error(`Skill load failed: ${err.message}`);
    process.exit(1);
  }
  throw err;
}

Prevention

When it happens

Trigger: A SKILL.md whose first line is not `---`; frontmatter missing the closing `---`; a YAML syntax error (bad indentation, unquoted colon); an unknown frontmatter key (typo like `descripton`); a `name` with uppercase letters, spaces, or >64 chars; a missing `name` or `description` field; body that is empty/whitespace (instructions required).

Common situations: Authoring a new skill and misspelling a frontmatter key; copy-pasting from a non-skill template that lacks frontmatter; editor auto-stripping the leading `---`; renaming a skill to a display name with spaces instead of the lowercase slug; CI loading a skill directory that contains a stale draft SKILL.md.

Related errors


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