siyuan-note/siyuan · error

marshal inline styles failed: %w

Error message

marshal inline styles failed: %w

What it means

After merging the incoming styles with the current AV state, the result is serialized with gulu.JSON.MarshalIndentJSON before being written to disk. A marshal failure here means the resulting InlineStyles structure could not be converted to JSON — typically caused by unsupported types or a MarshalJSON implementation error deeper in the structure. The write is aborted and the original file untouched.

Source

Thrown at kernel/model/inline_style.go:279

	if 0 < len(changedCustomColorIndexes) {
		removedIndexes := removedAttributeViewCustomColorIndexes(currentAV.Colors, ret.AV.Colors)
		customColorUsage, err = workspaceAttributeViewCustomColorUsage(0 < len(removedIndexes))
		if err != nil {
			return nil, false, err
		}
		for _, avID := range sortedAttributeViewUsageIDs(customColorUsage) {
			indexes := customColorUsage[avID]
			for index := range removedIndexes {
				if _, used := indexes[index]; used {
					return nil, false, fmt.Errorf("attribute view custom color [%d] is still in use by attribute view [%s]",
						index, avID)
				}
			}
		}
	}
	data, err := gulu.JSON.MarshalIndentJSON(ret, "", "  ")
	if err != nil {
		return nil, false, fmt.Errorf("marshal inline styles failed: %w", err)
	}
	if maxInlineStylesFileSize < len(data) {
		return nil, false, fmt.Errorf("inline styles file exceeds the %d byte limit", maxInlineStylesFileSize)
	}

	dataPath := inlineStylesPath()
	oldData, readErr := filelock.ReadFile(dataPath)
	if readErr != nil && !os.IsNotExist(readErr) {
		return nil, false, fmt.Errorf("read inline styles failed: %w", readErr)
	}
	if bytes.Equal(oldData, data) {
		cacheWorkspaceAVPalette(ret.AV)
		return ret, false, nil
	}

	if err = os.MkdirAll(filepath.Dir(dataPath), 0755); err != nil {
		return nil, false, fmt.Errorf("create inline styles directory failed: %w", err)
	}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Inspect any custom MarshalJSON on InlineStyles/InlineStyle types and fix the error it returns
  2. Remove or make JSON-serializable any non-standard fields added to the styles structures
  3. Log the underlying wrapped error (%w) to identify the exact field that failed
  4. Retry with a minimal payload (empty Styles) to confirm the failure comes from payload content

Example fix

// before
type InlineStyle struct { Callback func() `json:"cb"` } // json cannot marshal funcs
// after
type InlineStyle struct { Color string `json:"color"` }
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := json.Marshal(ret); err != nil {
    return fmt.Errorf("payload not serializable: %w", err)
}

Try / catch

_, _, err := model.SetInlineStyles(styles)
if err != nil && strings.HasPrefix(err.Error(), "marshal inline styles failed") {
    log.Fatalf("styles payload not serializable: %v", err)
}

Prevention

When it happens

Trigger: A custom type inside InlineStyles/InlineStyleAV (or injected fields) whose MarshalJSON returns an error; corrupted in-memory structures containing channels/funcs that json cannot encode (usually only possible via code modifications or plugin-supplied values).

Common situations: Custom kernel builds adding non-serializable fields to InlineStyles; middleware that stores arbitrary values into the styles map before persisting.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/46e3b8a51c3a1955. Report an issue: GitHub.