laurent22/joplin · error · Error

Non-inline asset missing required property "name"

Error message

Non-inline asset missing required property "name"

What it means

Thrown by PluginLoader when iterating loadedPlugin.assets() and encountering an asset with inline === false (or falsy) but no name property. Non-inline assets must reference an external CSS file by name so the loader can call plugin.loadCssAsset(asset.name) to fetch its contents. Without a name the loader cannot resolve the asset.

Source

Thrown at packages/editor/CodeMirror/pluginApi/PluginLoader.ts:166

			loadedPlugin.plugin?.(this.editor);

			if (loadedPlugin.codeMirrorOptions) {
				for (const key in loadedPlugin.codeMirrorOptions) {
					this.editor.setOption(key, loadedPlugin.codeMirrorOptions[key]);
				}
			}

			if (loadedPlugin.assets) {
				const cssStrings = [];

				for (const asset of loadedPlugin.assets()) {
					let assetText: string = asset.text;
					let assetMime: string = asset.mime;

					if (!asset.inline) {
						if (!asset.name) {
							throw new Error('Non-inline asset missing required property "name"');
						}
						if (assetMime !== 'text/css' && !asset.name.endsWith('.css')) {
							throw new Error(
								`Non-css assets are not supported by the CodeMirror 6 editor. (Asset path: ${asset.name})`,
							);
						}

						assetText = await plugin.loadCssAsset(asset.name);
						assetMime = 'text/css';
					}

					if (assetMime !== 'text/css') {
						throw new Error(
							'Plugin assets must have property "mime" set to "text/css" or have a filename ending with ".css"',
						);
					}

					cssStrings.push(assetText);

View on GitHub (pinned to 2654b33620)

Solutions

  1. If the CSS is a literal string, set asset.inline = true and asset.text = cssString.
  2. If the CSS is a file, set asset.name = 'styles.css' (or the actual filename) and ensure loadCssAsset can resolve it, and omit inline or set it false.
  3. Validate the asset object shape in plugin tests before publishing.

Example fix

// before
assets: () => [{ mime: 'text/css', text: '' }],
// after — inline literal
assets: () => [{ inline: true, mime: 'text/css', text: '.cm-editor { font-size: 14px }' }],
Defensive patterns

Strategy: validation

Validate before calling

function validateAsset(a) {
  if (!a.inline && !a.name) throw new Error('Non-inline asset needs a name');
  if (a.inline && (typeof a.text !== 'string')) throw new Error('Inline asset needs text');
}
assets().forEach(validateAsset);

Type guard

function isNamedNonInlineAsset(a) { return !a.inline && typeof a.name === 'string' && a.name.length > 0; }

Try / catch

try {
  loader.setPlugins(contentScripts);
} catch (e) {
  if (/Non-inline asset missing required property/.test(e.message)) {
    // notify plugin author to add name or switch to inline
  } else throw e;
}

Prevention

When it happens

Trigger: A plugin asset object is { inline: false, mime: 'text/css' } with text omitted and name omitted; the asset was meant to be inline but inline was not set and text is empty; a typo set name to undefined.

Common situations: Plugin author intended an inline asset but forgot to set inline: true and omitted name; asset object built dynamically and name came back undefined; migration from the rich-text editor plugin API which had different asset requirements.

Related errors


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