siyuan-note/siyuan · error

invalid session id

Error message

invalid session id

What it means

gulu.JSON.UnmarshalJSON failed to decode the contents of ~/.config/siyuan/workspace.json into []string inside util.ReadWorkspacePaths. The file exists but is not valid JSON of the expected shape — typically a JSON array of workspace path strings. Corruption usually comes from manual edits, a truncated write (crash during save), or another tool rewriting the file.

Source

Thrown at kernel/agent/runtime.go:125

	mode, err := resolveSessionPermissionModeLocked(sessionID, nil)
	if err != nil {
		return nil, err
	}
	controller.allowSession.Store(mode == AgentPermissionAllowSession)
	sessionPermissionControllers.Store(sessionID, controller)
	return controller, nil
}

func unregisterSessionPermissionController(sessionID string, controller *sessionPermissionController) {
	if sessionID == "" || controller == nil {
		return
	}
	sessionPermissionControllers.CompareAndDelete(sessionID, controller)
}

func SetSessionPermissionMode(sessionID, mode string) error {
	if sessionID == "" || !isValidSessionID(sessionID) {
		return fmt.Errorf("invalid session id")
	}
	if !validAgentPermissionMode(mode) {
		return fmt.Errorf("invalid agent permission mode")
	}
	lock := sessionLock(sessionID)
	lock.Lock()
	defer lock.Unlock()
	if _, err := os.Stat(filepath.Join(sessionsDir(), sessionID, "session.json")); err != nil {
		return err
	}
	runtime, err := loadRuntimeLocked(sessionID)
	if err != nil {
		return err
	}
	runtime.PermissionMode = mode
	runtime.AlwaysAllow = false
	if err = writeRuntimeLocked(sessionID, runtime); err != nil {
		return err

View on GitHub (pinned to afa823b6b4)

Solutions

  1. Open ~/.config/siyuan/workspace.json and validate it: it must be a plain JSON array of strings, e.g. ["/home/me/SiYuan"]
  2. Fix the syntax error, or simply delete/rename the file — the app treats it as fresh state and re-registers the current workspace
  3. If workspaces listed there matter, note the paths first, then recreate the file with those paths as a clean array
  4. Exclude ~/.config/siyuan from sync/merge tools to avoid conflict-corrupted writes in the future

Example fix

// before (corrupt)
["/home/me/SiYuan", "/data/ws",]

// after (valid)
[
  "/home/me/SiYuan",
  "/data/ws"
]
Defensive patterns

Strategy: validation

Validate before calling

data, err := os.ReadFile(workspaceConf)
if err == nil && !json.Valid(data) {
    // refuse to hand corrupt config to the kernel; back it up and start fresh
    _ = os.Rename(workspaceConf, workspaceConf+".bak")
}

Type guard

func isValidWorkspaceConf(data []byte) bool {
    var paths []string
    return json.Unmarshal(data, &paths) == nil
}

Try / catch

paths, err := util.ReadWorkspacePaths()
if err != nil && strings.Contains(err.Error(), "unmarshal workspace conf") {
    _ = os.Rename(workspaceConf, workspaceConf+".corrupt")
    paths, err = util.ReadWorkspacePaths() // regenerates from fresh state
}

Prevention

When it happens

Trigger: Hand-editing workspace.json and leaving a trailing comma/missing bracket; the process being killed mid-write leaving a partial file; replacing the file with an object {"path": ...} instead of an array; encoding issues (BOM, double UTF-8 encoding) from external editors.

Common situations: Users manually reordering or pruning workspace entries; power loss during workspace switching; sync tools (Dropbox etc.) conflict-merging the dotfile; scripts generating the file with a different schema.

Related errors


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