siyuan-note/siyuan · error
no supported frontend
Error message
no supported frontend
What it means
Thrown by normalizeBootAppearanceFrontends when after normalization no usable frontend remains: declared frontends were all invalid, or plugin frontends filtered everything out while manifestFrontends was empty. The default [desktop, mobile] is only applied when both input lists are completely empty.
Source
Thrown at kernel/model/boot_appearance.go:728
normalized = "desktop"
case "mobile":
normalized = "mobile"
default:
if len(manifestFrontends) > 0 {
return nil, fmt.Errorf("unsupported frontend [%s]", frontend)
}
continue
}
if !seen[normalized] {
seen[normalized] = true
frontends = append(frontends, normalized)
}
}
if len(frontends) == 0 && len(manifestFrontends) == 0 && len(pluginFrontends) == 0 {
frontends = append(frontends, "desktop", "mobile")
}
if len(frontends) == 0 {
return nil, errors.New("no supported frontend")
}
return frontends, nil
}
func validateOptionalBootAppearanceColor(color string) error {
if color != "" && !bootAppearanceColorPattern.MatchString(color) {
return fmt.Errorf("invalid color [%s]", color)
}
return nil
}
func isValidBootAppearanceID(id string) bool {
return len(id) <= 64 && bootAppearanceIDPattern.MatchString(id)
}
func isSafeBootAppearanceRelativePath(relativePath string) bool {
if relativePath == "" || len(relativePath) > maxBootAppearancePathLength || strings.Contains(relativePath, "\\") ||
strings.ContainsAny(relativePath, `<>:"|?*`) || strings.HasPrefix(relativePath, "/") ||View on GitHub (pinned to 8641553a1f)
Solutions
- Set manifest frontends to ["desktop"], ["mobile"], or ["desktop","mobile"].
- If using plugin frontends, ensure they include at least desktop or mobile.
- Remove the conflicting plugin frontend declarations so the defaults apply.
Example fix
// before "frontends": [] // plugin declares only unsupported frontends // after "frontends": ["desktop", "mobile"]
Defensive patterns
Strategy: validation
Validate before calling
function resolvesToFrontend(manifestF, pluginF) { const has = a => (a || []).some(f => f === "desktop" || f === "mobile"); return has(manifestF) ? has(manifestF) : (has(pluginF) || ((manifestF || []).length === 0 && (pluginF || []).length === 0)); } Try / catch
try { await installBootAppearance(pkg); } catch (e) { if (String(e).includes("no supported frontend")) { /* declare desktop/mobile in manifest frontends */ } else throw e; } Prevention
- Always declare frontends explicitly in the manifest
- Ensure plugin frontend lists intersect with desktop/mobile
- Test package load before distribution
When it happens
Trigger: Manifest omits frontends (so the manifest defaults do not run) but the plugin's frontends list excludes both desktop and mobile; or an empty-but-present combination leaves len(frontends)==0 with non-empty pluginFrontends.
Common situations: A plugin package targeting only an unsupported frontend, or configuration drift between the manifest and the plugin's declared frontends.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- unsupported frontend [%s]
- 199
- invalid marketplace package manifest
- too many layers: %d
- invalid or duplicate layer ID
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/d10d57d311a1610f.
Report an issue: GitHub.