Jump to your error
- missing "key"
- "version" must be a str, not a list
- to be a semantic-version, found …
- "license" must be a list, not a str
- "license" invalid: list may not be empty
- no longer than 64 characters expected
- must not end with punctuation
- "id" invalid: Not a valid identifier
- Only single separators are supported
- must not start / end with a "_"
- "tags" must be a list, not a str
- found invalid tag "…" not found in
- expected 3 numbers separated by "."
- Expected to be one of [theme, add-on]
- value of "network" must be a string
- must be a value in ('microphone', …)
- a non-empty string expected
- file missing from add-on: "__init__.py"
- Accepted here, rejected later
- The valid tag list
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.
- 3D View
- Add Curve
- Add Mesh
- Animation
- Bake
- Camera
- Compositing
- Development
- Game Engine
- Geometry Nodes
- Grease Pencil
- Import-Export
- Lighting
- Material
- Mesh
- Modeling
- Node
- Object
- Paint
- Physics
- Pipeline
- Render
- Rigging
- Scene
- Sculpt
- Sequencer
- System
- Text Editor
- Tracking
- User Interface
- UV
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)