Blender extension manifest errors, and what each one means

Every message blender --command extension validate prints for a blender_manifest.toml, quoted exactly as Blender emits it, with the cause and the fix. Then the mistakes validate accepts but the extensions platform does not, and the full list of tags an add-on may use.

Messages below are from Blender 4.2 LTS. Most of them never appear if you generate the manifest with the bl_info converter.

missing "key"

Error parsing TOML "blender_manifest.toml"
missing "license"

Nine keys are required, and each absent one is reported on its own line: schema_version, id, version, name, tagline, maintainer, type, license, blender_version_min. Four of them have no equivalent in a legacy bl_info dict — schema_version, tagline, license and type — so a hand-migrated manifest usually trips this first.

"version" must be a str, not a list

Error parsing TOML "blender_manifest.toml"
"version" must be a str, not a list

A bl_info version was a tuple. A manifest version is a quoted string.

version = [1, 4, 2]
version = "1.4.2"

key "version" invalid: to be a semantic-version, found '…'

key "version" invalid: to be a semantic-version, found '1.4'
key "version" invalid: to be a semantic-version, found 'v1.4.2'
key "version" invalid: to be a semantic-version, found '1.4.2.1'

Exactly three dot-separated numbers, no v prefix. A two-part (1, 4) tuple becomes "1.4.0", not "1.4".

"license" must be a list, not a str

Error parsing TOML "blender_manifest.toml"
"license" must be a list, not a str

An extension may carry several licences, so the field is always a list even with one entry.

license = "SPDX:GPL-3.0-or-later"
license = ["SPDX:GPL-3.0-or-later"]

key "license" invalid: list may not be empty

key "license" invalid: list may not be empty

license = [] is not a way to leave it undecided, and validate does not care which licence you name — but the platform does. Its licence rules require GPL-3.0-or-later for add-ons; themes may use any GPL-compatible licence, and assets bundled inside an add-on must be CC0.

license = ["SPDX:GPL-3.0-or-later"]

key "tagline" invalid: a value no longer than 64 characters expected

key "tagline" invalid: a value no longer than 64 characters expected, found 65

The limit is 64 inclusive — 64 passes, 65 fails. The count is characters, not words. A legacy description is usually longer, so it has to be cut down rather than copied across.

key "tagline" invalid: alpha-numeric suffix expected

key "tagline" invalid: alpha-numeric suffix expected, the string must not end with punctuation

A tagline is a label, not a sentence, so it may not end in . , ; : ! or ?. Only the last character is checked; punctuation inside is fine. name has no such rule.

tagline = "Align selected meshes to the active object."
tagline = "Align selected meshes to the active object"

key "id" invalid: Not a valid identifier

key "id" invalid: Not a valid identifier

The id becomes a Python module name, so it must be a legal Python identifier: letters, digits and underscores, never starting with a digit. Hyphens and spaces are the usual cause.

id = "mesh-aligner"   id = "3d_aligner"
id = "mesh_aligner"   id = "aligner_3d"

key "id" invalid: Only single separators are supported

key "id" invalid: Only single separators are supported

Two underscores in a row. mesh__aligner has to become mesh_aligner.

key "id" invalid: Names must not start / end with a "_"

key "id" invalid: Names must not start with a "_"
key "id" invalid: Names must not end with a "_"

A leading underscore is the Python convention for private, and neither end may carry one. Strip it.

"tags" must be a list, not a str

Error parsing TOML "blender_manifest.toml"
"tags" must be a list, not a str

The single category string of bl_info became a list of tags.

tags = "Mesh"
tags = ["Mesh"]

found invalid tag "…" not found in (…)

FATAL_ERROR: Error in TOML "blender_manifest.toml" loading tags: found invalid tag "VFX" not found in:
(3D View, Add Curve, Add Mesh, All, Animation, Bake, …)
Either correct the tag or disable validation using an empty tags argument --valid-tags="", see --help text for details.

Tags come from a fixed vocabulary and are case-sensitive — the full list is below. Several plausible-sounding words are not in it: VFX, Retopology, Hair, Simulation, Shading. Legacy category values that no longer exist as tags have to be remapped by hand.

The suggested --valid-tags="" switches the check off. It makes the message go away without making the tag valid, so it is only useful when you are packaging for somewhere other than extensions.blender.org.

key "blender_version_min" invalid: expected 3 numbers separated by "."

key "blender_version_min" invalid: expected 3 numbers separated by ".", found "4.2"

Three components, so "4.2.0" rather than "4.2". Blender itself accepts shorter forms; the extensions platform does not, and validate applies the platform's stricter rule.

key "type" invalid: Expected to be one of [theme, add-on]

key "type" invalid: Expected to be one of [theme, add-on], found 'addon'

Hyphenated and lowercase: type = "add-on". Not addon, not Add-on.

key "permissions" invalid: value of "network" must be a string

key "permissions" invalid: value of "network" must be a string not a <class 'bool'>

A permission's value is the reason it is needed, shown to the person installing your add-on. true is not a reason.

[permissions]
network = true
network = "Check the author's site for updates"

value of "…" must be a value in ('microphone', 'network', 'files', 'clipboard', 'camera')

key "permissions" invalid: value of "telemetry" must be a value in ('microphone', 'network', 'files', 'clipboard', 'camera')

Those five are the whole vocabulary — camera, clipboard, files, microphone, network. Anything else is rejected, and each one you do declare needs a plain-language reason as its value.

key "maintainer" invalid: a non-empty string expected

key "maintainer" invalid: a non-empty string expected

maintainer = "" does not satisfy the required key. The conventional form is "Name <email@example.com>".

Error, file missing from add-on: "__init__.py"

Error, file missing from add-on: "__init__.py"

An add-on is a package. blender_manifest.toml and __init__.py sit together at the top level — not inside a further folder, and not alongside a single-file my_addon.py. A single-file add-on has to become a directory before it can be an extension.

Accepted by validate, rejected later

These pass extension validate and extension build without a word, so a clean local run is not proof the manifest is right. Each one conflicts with the published manifest schema or with the platform's submission rules.

A licence with no SPDX: prefix

license = ["GPL-3.0-or-later"] validates. So does license = ["SPDX:Not-A-Real-Licence"] — the local check is only that the list is non-empty strings, and no identifier is looked up. The schema specifies SPDX identifiers carrying the prefix: license = ["SPDX:GPL-3.0-or-later"].

blender_version_min below 4.2.0

"2.93.0" validates cleanly, because the rule checked is the three-number shape rather than the value. Extensions do not exist before 4.2, so a legacy "blender": (2, 93, 0) carried across is wrong even though nothing complains.

Keys that do not exist

Unrecognised keys are ignored silently. A leftover category = "Mesh" produces no warning and no tag — the field it looks like it should populate is tags, and that stays empty.

No tags at all

tags is optional to validate. Omitting it ships an extension that appears under no category in Blender's browser and in the store's filters.

An id that is not lowercase

id = "MeshAligner" is a legal Python identifier and passes. Every listed extension uses lowercase with underscores, and the id is permanent once published.

A maintainer with no email address

maintainer = "Jo Smith" passes. The platform expects a contact, and it is the only route it has to reach you about a listing.

bl_info still in __init__.py

Never checked. Blender 4.2 reads the manifest and ignores the dict, so the two silently disagree — the stale copy is what any other tool, and any human, reads first. Delete it.

A schema_version that is not 1.0.0

The field is only checked for the shape of a version number, so schema_version = "2.0.0" validates. "1.0.0" is the version the schema defines and the one every Blender template writes.

The valid tag list

Every tag an add-on may declare, exactly as spelled. Case-sensitive, and anything not on this list is a fatal error.

Blender also accepts All, which it assigns to legacy add-ons that never carried a category. It is not a useful choice for a new extension.

Themes use a separate vocabulary: Accessibility, Colorful, Dark, High Contrast, Inspired By, Light, Print.

A manifest that validates

Minimal and complete — every required key, nothing that trips a rule above.

schema_version = "1.0.0"

id = "mesh_aligner"
version = "1.4.2"
name = "Mesh Aligner"
tagline = "Align selected meshes to the active object"
maintainer = "Jo Smith <jo@example.com>"
type = "add-on"

license = ["SPDX:GPL-3.0-or-later"]
blender_version_min = "4.2.0"
tags = ["Mesh"]

Check it, then build it:

blender --command extension validate .
blender --command extension build

Validate reads the manifest. It does not run your Python, so it cannot tell you whether the add-on registers — install the built zip once before you upload it.

Paste a bl_info dict and get this manifest generated — free, runs in your browser, nothing uploaded.

Card Normals is a free add-on that makes hair, foliage and grass cards shade as one volume.

Hair Cards — hair curves to game-ready cards in one click, $29. In development.

One question, if you have ten seconds

Which repetitive Blender chore would you pay to never do again? One sentence is plenty.

Answer on GitHub → (no newsletter, no follow-up)