cloudreve/cloudreve · warning

failed to marshal state: %w

Error message

failed to marshal state: %w

What it means

saveState serializes the in-memory State with json.Marshal before writing it to disk. Every State field is a JSON-encodable primitive or map (ints, strings, map[int]bool, map[uint]string), so in the shipped code this error is effectively unreachable: encoding/json only fails on unsupported values such as funcs, channels, complex numbers, NaN floats, or cyclic pointer structures. Encountering it means a custom build added a non-serializable field to State.

Source

Thrown at application/migrator/migrator.go:158

	err = model.Init()
	if err != nil {
		return nil, err
	}

	v4client, err := inventory.NewRawEntClient(m.l, m.dep.ConfigProvider())
	if err != nil {
		return nil, err
	}

	m.v4client = v4client
	return m, nil
}

// saveState persists migration state to file
func (m *Migrator) saveState() error {
	data, err := json.Marshal(m.state)
	if err != nil {
		return fmt.Errorf("failed to marshal state: %w", err)
	}

	return os.WriteFile(m.statePath, data, 0644)
}

// loadState reads migration state from file
func (m *Migrator) loadState() error {
	data, err := os.ReadFile(m.statePath)
	if err != nil {
		return fmt.Errorf("failed to read state file: %w", err)
	}

	return json.Unmarshal(data, m.state)
}

// updateStep updates current step and persists state
func (m *Migrator) updateStep(step int) error {
	m.state.Step = step

View on GitHub (pinned to 20c95ad73f)

Solutions

  1. Inspect the State struct for func/chan/complex fields or custom MarshalJSON implementations and remove them.
  2. Keep State limited to plain primitives, strings, slices, and maps of those.
  3. Add a unit test that round-trips State through json.Marshal/json.Unmarshal to catch regressions in CI.
Defensive patterns

Strategy: validation

Validate before calling

// CI regression guard: State must always be JSON-marshalable.
func TestStateSerializable(t *testing.T) {
	s := &State{PolicyIDs: map[int]bool{1: true}, Step: StepGroup}
	if _, err := json.Marshal(s); err != nil {
		t.Fatalf("State is not serializable: %v", err)
	}
}

Prevention

When it happens

Trigger: A fork or patch adds a field of type func(), chan, or complex128 to State; a float field holds NaN; State references a type whose custom MarshalJSON returns an error.

Common situations: Custom Cloudreve builds; third-party patches that extend the migration State struct without testing persistence.

Related errors


AI-assisted analysis of cloudreve/cloudreve@20c95ad73f (2026-08-16). Data as JSON: /api/errors/e37d3fc83ea82306. Report an issue: GitHub.