laurent22/joplin · error · Error

Manifest plugin ID is not set in ${manifestPath}

Error message

Manifest plugin ID is not set in ${manifestPath}

What it means

Thrown by readManifest() right after JSON.parse of manifest.json. The plugin id is the unique identifier used by Joplin to register and update the plugin; it cannot be empty. The check is `if (!output.id)`, so missing, empty-string, or null all trigger it.

Source

Thrown at packages/generator-joplin/generators/app/templates/webpack.config.js:125

			continue;
		}

		const screenshotType = screenshot.src.split('.').pop();
		if (!allPossibleScreenshotsType.includes(screenshotType)) throw new Error(`${screenshotType} is not a valid screenshot type. Valid types are: \n${allPossibleScreenshotsType}\n`);

		const screenshotPath = path.resolve(rootDir, screenshot.src);

		// Max file size is 1MB
		const fileMaxSize = 1024;
		const fileSize = fs.statSync(screenshotPath).size / 1024;
		if (fileSize > fileMaxSize) throw new Error(`Max screenshot file size is ${fileMaxSize}KB. ${screenshotPath} is ${fileSize}KB`);
	}
}

function readManifest(manifestPath) {
	const content = fs.readFileSync(manifestPath, 'utf8');
	const output = JSON.parse(content);
	if (!output.id) throw new Error(`Manifest plugin ID is not set in ${manifestPath}`);
	validateCategories(output.categories);
	validateScreenshots(output.screenshots);
	return output;
}

function createPluginArchive(sourceDir, destPath) {
	const distFiles = glob.sync(`${sourceDir}/**/*`, { nodir: true, windowsPathsNoEscape: true })
		.map(f => f.substr(sourceDir.length + 1));

	if (!distFiles.length) throw new Error('Plugin archive was not created because the "dist" directory is empty');
	fs.removeSync(destPath);

	tar.create(
		{
			strict: true,
			portable: true,
			file: destPath,
			cwd: sourceDir,

View on GitHub (pinned to 2654b33620)

Solutions

  1. Open manifest.json and add a unique `id` (typically a reverse-DNS or slug-style identifier, e.g. "com.example.my-plugin").
  2. Ensure the id is unique across the Joplin plugin repository to avoid collisions.
  3. Re-run the build.

Example fix

// before (manifest.json)
{ "version": "1.0.0", "app_min_version": "2.6" }
// after
{ "id": "com.example.my-plugin", "version": "1.0.0", "app_min_version": "2.6" }
Defensive patterns

Strategy: validation

Validate before calling

const manifest = require('./manifest.json');
if (!manifest.id || typeof manifest.id !== 'string') {
  throw new Error('manifest.json must define a non-empty string `id`');
}

Type guard

const hasId = (m) => !!m && typeof m.id === 'string' && m.id.length > 0;

Try / catch

try { readManifest(manifestPath); }
catch (e) { if (/plugin ID is not set/.test(e.message)) { /* prompt for an id */ } else throw e; }

Prevention

When it happens

Trigger: manifest.json parses successfully but has no `id` field, or `id` is set to "" or null.

Common situations: New plugin scaffold where the id was not filled in; field accidentally deleted during a manual edit; key renamed to `pluginId` or `name`.

Related errors


AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12). Data as JSON: /api/errors/186ed40e815139ee. Report an issue: GitHub.