siyuan-note/siyuan · error
read-only mode
Error message
read-only mode
What it means
SetBootAppearance modifies the persisted boot (splash) appearance selection, but the kernel is running in read-only mode (util.ReadOnly), so configuration writes are disabled and the call returns the default selection with this error. Read-only mode is a runtime state (e.g. readonly launch flag / protected environments) in which no data or config mutation is permitted.
Source
Thrown at kernel/model/boot_appearance.go:214
// GetBootAppearance 返回当前可用的启动页外观,任何异常和安全模式下均回退默认。
func GetBootAppearance() *BootAppearance {
if util.SafeMode {
return &BootAppearance{Enabled: false}
}
selection, appearance, err := loadSelectedBootAppearance()
if err != nil {
return &BootAppearance{Enabled: false}
}
if selection.Provider == "" || selection.Appearance == "" {
return &BootAppearance{Enabled: false}
}
return appearance
}
// SetBootAppearance 校验并原子持久化启动页外观选择,两项均为空表示恢复默认。
func SetBootAppearance(provider, appearanceID string) (ret BootAppearanceSelection, err error) {
if util.ReadOnly {
return defaultBootAppearanceSelection(), errors.New("read-only mode")
}
provider = strings.TrimSpace(provider)
appearanceID = strings.TrimSpace(appearanceID)
ret = defaultBootAppearanceSelection()
if (provider == "") != (appearanceID == "") {
err = errors.New("provider and appearance must both be empty or non-empty")
return
}
if provider != "" {
if !bazaar.IsValidPackageName(provider) || !isValidBootAppearanceID(appearanceID) {
err = ErrBootAppearanceNotFound
return
}
if _, resolveErr := getBootAppearanceByID(provider, appearanceID); resolveErr != nil {
err = ErrBootAppearanceNotFound
return
}
ret.Provider, ret.Appearance = provider, appearanceIDView on GitHub (pinned to 8641553a1f)
Solutions
- Restart the kernel without read-only mode, then call SetBootAppearance.
- Skip the customization step when util.ReadOnly is true; treat the default selection as final.
- If read-only is unintentional, check the launch configuration/flags that set util.ReadOnly.
- Use the returned defaultBootAppearanceSelection() as a safe fallback in callers.
Example fix
// before
_, err := model.SetBootAppearance(provider, id)
// after
if util.ReadOnly {
return model.DefaultBootAppearanceSelection() // skip write in read-only mode
}
_, err := model.SetBootAppearance(provider, id) Defensive patterns
Strategy: fallback
Validate before calling
if (kernelReadOnly) skipAppearanceCustomization()
Try / catch
sel, err := model.SetBootAppearance(provider, id)
if err != nil && strings.Contains(err.Error(), "read-only mode") {
sel = model.DefaultBootAppearanceSelection()
} Prevention
- Check util.ReadOnly before attempting any config writes
- Design tooling to treat read-only instances as non-configurable
- Surface read-only state in UI before offering customization
When it happens
Trigger: Calling SetBootAppearance (via setBootAppearance API or tests) while the kernel runs with read-only mode enabled; attempting to persist any boot appearance selection in a locked/readonly workspace.
Common situations: Kernel started with the readonly flag for kiosk/public deployments; automated tooling trying to customize the splash screen on a read-only instance.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- invalid boot appearance selection
- Please initialize the data repo key first in [Settings - Acc
- This operation is not supported in read-only mode
- invalid agent permission mode
- provider base URL is required
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/f55072265741546b.
Report an issue: GitHub.