siyuan-note/siyuan · error
name must end in .html or .htm
Error message
name must end in .html or .htm
What it means
`normalizeHTMLAssetName` requires the supplied asset file name to end in `.html` or `.htm` (case-insensitive). The HTML asset feature stores a single HTML file that gets embedded via an `<iframe>`, so only HTML extensions are accepted; any other extension is rejected before the file is written.
Source
Thrown at kernel/mcp/tools/asset.go:176
Content: []ContentItem{{Type: "text", Text: fmt.Sprintf("Created HTML IFrame block: %s\nAsset: %s", blockID, assetPath)}},
StructuredContent: map[string]any{
"blockID": blockID,
"assetPath": assetPath,
},
StructuredContentSet: true,
}, nil
}
func normalizeHTMLAssetName(value any) (string, error) {
name, _ := value.(string)
name = strings.TrimSpace(name)
if name == "" {
name = "component.html"
}
name = filepath.Base(name)
ext := strings.ToLower(filepath.Ext(name))
if ext != ".html" && ext != ".htm" {
return "", fmt.Errorf("name must end in .html or .htm")
}
return name, nil
}
func htmlAssetIFrameBlockDOM(assetPath string) (dom, blockID string, err error) {
src := html.EscapeString(model.HTMLAssetIFrameSrc(assetPath))
dom, err = markdownToBlockDOM(`<iframe sandbox="allow-scripts" src="` + src + `" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe>`)
if err != nil {
return
}
tree := util.NewLute().BlockDOM2Tree(dom)
if tree == nil || tree.Root == nil || tree.Root.FirstChild == nil {
return "", "", fmt.Errorf("empty IFrame block")
}
blockID = tree.Root.FirstChild.ID
return
}
View on GitHub (pinned to 251596fc0d)
Solutions
- Supply a `name` ending in `.html` (or `.htm`), e.g. `component.html`.
- If `name` is omitted it defaults to `component.html`; only override it with another `.html`/`.htm` value.
- Remember only `filepath.Base` is kept, so directories in the value are ignored — set the extension on the filename itself.
Example fix
// before
{"name": "widget.js", "content": "..."}
// after
{"name": "widget.html", "content": "..."} Defensive patterns
Strategy: validation
Validate before calling
// Validate the asset name extension before calling the tool.
func validHTMLName(name string) bool {
ext := strings.ToLower(filepath.Ext(strings.TrimSpace(name)))
return ext == ".html" || ext == ".htm"
} Prevention
- Default to `component.html` when unsure.
- Set the extension on the filename itself (directories are stripped by filepath.Base).
- Reject non-.html/.htm names client-side before invoking the tool.
When it happens
Trigger: Calling the HTML-asset MCP tool with a `name` argument whose extension (after `filepath.Base` and lowercasing) is neither `.html` nor `.htm` — e.g. `.txt`, `.svg`, `.js`, or no extension at all.
Common situations: Passing a full path whose final component has a different extension. Providing a component name like `widget.js` when an HTML wrapper is required. Forgetting the extension entirely.
Related errors
- invalid tool arguments: %w
- empty result
- path is required
- path escapes templates dir: %s
- invalid asset type [%s]
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/c01d8dd92f2094c3.
Report an issue: GitHub.