siyuan-note/siyuan · warning

This operation is not supported in read-only mode

Error message

This operation is not supported in read-only mode

What it means

Returned by the onboarding flow (model/onboarding.go) when a new user with an incomplete onboarding state calls an onboarding-advancing API while the kernel runs with util.ReadOnly (launched with --readonly / read-only workspace) or with the publish service enabled (Conf.Publish.Enable). Read-only and publish modes cannot create the onboarding notebook/document, so the operation is refused with Language(34).

Solutions

  1. Complete onboarding once in a normal read-write, non-publish session on the same workspace, then re-enable read-only/publish mode
  2. Disable publish mode (Conf.Publish.Enable=false) or stop using --readonly so onboarding can create its notebook/document
  3. Provision the workspace by pre-seeding the onboarding notebook/document IDs (onboarding.NotebookID/DocumentID with the .sy present) so reconcileOnboarding marks it complete
  4. If the workspace was never meant to onboard, set the onboarding state to completed via config instead of calling the advancing API

Example fix

// before
// kernel started with --readonly, new user calls onboarding API
model.AdvanceOnboarding(...) // -> Language(34)

// after
// guard the call site
if util.ReadOnly || Conf.Publish.Enable {
    http.Error(w, "onboarding unavailable in read-only/publish mode", http.StatusConflict)
    return
}
model.AdvanceOnboarding(...)
Defensive patterns

Strategy: validation

Validate before calling

if util.ReadOnly || Conf.Publish.Enable {
    // skip/queue onboarding-advancing calls; they will fail with Language(34)
    return nil
}

Type guard

func onboardingAllowed() bool {
    return !util.ReadOnly && !Conf.Publish.Enable
}

Try / catch

if _, _, err := model.GetOnboarding(); err != nil {
    if err.Error() == Conf.Language(34) {
        // surface 'complete onboarding in a read-write session' to the operator
    }
}

Prevention

When it happens

Trigger: Calling the onboarding/status-advancing API on a workspace booted in read-only mode or with publish enabled while onboarding.NewUser is true and State is not conf.OnboardingCompleted. Note the guard only fires for incomplete onboarding: completed or non-new-user sessions return cleanly.

Common situations: Publish-service deployments (Conf.Publish.Enable) pointed at a fresh workspace that never completed first-run onboarding; kernels started with --readonly for demo/inspection purposes on a new data dir; Docker/publish images provisioned without running the interactive first-boot flow.

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/229e35aff87bf204. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/onboarding.go:109

	onboarding := Conf.Onboarding
	if !onboarding.NewUser || onboarding.Dismissed {
		return cloneOnboarding(onboarding), false, nil
	}

	boxes, listErr := ListNotebooks()
	if listErr != nil {
		return cloneOnboarding(onboarding), false, listErr
	}
	documentExists := onboarding.NotebookID != "" && onboarding.DocumentID != "" && filelock.IsExist(filepath.Join(
		util.DataDir, onboarding.NotebookID, onboarding.DocumentID+".sy"))
	if reconcileOnboarding(onboarding, boxes, documentExists) {
		Conf.Save()
	}
	if !onboarding.NewUser || onboarding.State == conf.OnboardingCompleted {
		return cloneOnboarding(onboarding), false, nil
	}
	if util.ReadOnly || Conf.Publish.Enable {
		return cloneOnboarding(onboarding), false, errors.New(Conf.Language(34))
	}

	if onboarding.NotebookID == "" {
		if len(boxes) > 0 {
			if len(boxes) == 1 && boxes[0].Name == Conf.Language(342) {
				onboarding.NotebookID = boxes[0].ID
				onboarding.State = conf.OnboardingNotebookCreated
				Conf.Save()
			} else {
				onboarding.State = conf.OnboardingCompleted
				onboarding.NewUser = false
				Conf.Save()
				return cloneOnboarding(onboarding), false, nil
			}
		}

		if onboarding.NotebookID == "" {
			onboarding.NotebookID, err = CreateBox(Conf.Language(342))

View on GitHub (pinned to afa823b6b4)