siyuan-note/siyuan · error

decode session data failed

Error message

decode session data failed: %w

What it means

After metadata validation, SaveSessionState decodes the full payload into a generic map. If that second gulu.JSON.UnmarshalJSON fails, it wraps the underlying error as "decode session data failed: %w". This catches payloads that parse for sessionMeta but are not valid JSON overall, or contain structurally incompatible values for the full decode pass.

Solutions

  1. Inspect the wrapped inner error (%w) to find the exact JSON syntax offset
  2. Re-send the full, complete session JSON from the client
  3. Fix the client serializer to emit strict JSON (no NaN, no trailing commas)
  4. Validate the payload with a strict JSON parser client-side before sending

Example fix

// before
payload := fmt.Sprintf("{"id":%q,,"entries":%v}", id, entries) // malformed
SaveSessionState([]byte(payload))
// after
payload, err := json.Marshal(sessionObj)
if err != nil { return err }
SaveSessionState(payload)
Defensive patterns

Strategy: try-catch

Validate before calling

var probe any
if err := json.Unmarshal(payload, &probe); err != nil { /* fix payload before sending */ }

Try / catch

if _, _, err := SaveSessionState(data); err != nil && strings.HasPrefix(err.Error(), "decode session data failed") {
    var perr *json.SyntaxError
    if errors.As(err, &perr) { log.Printf("bad JSON at offset %d", perr.Offset) }
}

Prevention

When it happens

Trigger: Sending truncated or syntactically invalid JSON (metadata parse succeeded earlier only if the error appeared later in the body — otherwise see error 107); duplicating or corrupting bytes during transport; a custom encoder emitting invalid JSON (NaN, trailing commas).

Common situations: Interrupted uploads leaving partial bodies; proxy/encoding layers mangling the payload; client bug writing NaN/Infinity into numeric fields.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/ea1696ccf17c89a8. Report an issue: GitHub.

Appendix: source

Thrown at kernel/agent/session.go:334

	revision, _, err := SaveSessionState(data)
	return revision, err
}

func SaveSessionState(data []byte) (int64, map[string]any, error) {
	var meta sessionMeta
	if err := gulu.JSON.UnmarshalJSON(data, &meta); err != nil || meta.ID == "" || !isValidSessionID(meta.ID) {
		return 0, nil, fmt.Errorf("invalid session data")
	}
	lock := sessionLock(meta.ID)
	lock.Lock()
	defer lock.Unlock()

	dir := filepath.Join(sessionsDir(), meta.ID)
	path := filepath.Join(dir, "session.json")

	var newData map[string]any
	if err := gulu.JSON.UnmarshalJSON(data, &newData); err != nil {
		return 0, nil, fmt.Errorf("decode session data failed: %w", err)
	}
	delete(newData, "expectedRevision")
	delete(newData, "commitTurnID")
	delete(newData, "recoveryTurnID")
	delete(newData, "recoveryState")
	delete(newData, "recoveryRevision")
	delete(newData, "agentRunning")
	delete(newData, "lastCommittedTurnID")
	commitTurnID := meta.CommitTurnID
	if commitTurnID == "" {
		commitTurnID = meta.RecoveryTurnID
	}

	currentRevision := int64(0)
	currentCommittedTurnID := ""
	existing, err := os.ReadFile(path)
	if err == nil && len(existing) > 0 {
		var existingData map[string]any

View on GitHub (pinned to 9f775e8a12)