dotnet/wpf · error · SystemException
SR.Format(SR.CustomContentStateMustBeSerializable, type)
Error message
SR.Format(SR.CustomContentStateMustBeSerializable, type)
What it means
When saving a journal entry that carries a CustomContentState, the service verifies the state object's type is serializable. Non-serializable CustomContentState objects cannot survive journal serialization (e.g. saving to disk for Remember navigation), so a SystemException is thrown naming the offending type.
Solutions
- Mark the CustomContentState class [Serializable] and implement ISerializable correctly.
- Ensure all fields of the CustomContentState are serializable types.
- Store non-serializable data by reference/key and rebuild it in Reapply().
- Test journal save/load early in development of custom state.
Example fix
// before
class MyState : CustomContentState { public MyControl C; }
// after
[Serializable]
class MyState : CustomContentState {
public string ControlId; // serializable data instead of live control
public override void Reapply(object navigationContent, NavigationMode mode) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
bool stateIsSerializable(CustomContentState ccs) => ccs == null || ccs.GetType().IsSerializable;
Type guard
bool IsSerializableState<T>(T state) where T : CustomContentState => state.GetType().IsSerializable;
Try / catch
try { navService.AddBackEntry(myState); }
catch (SystemException ex) when (ex.Message.Contains("serializable"))
{ /* log type and fix [Serializable] */ } Prevention
- Always mark CustomContentState subclasses [Serializable].
- Keep state fields to serializable primitives.
- Add a unit test that round-trips state via a BinaryFormatter/MemoryStream.
- Store live controls by identifier, rebuild in Reapply.
When it happens
Trigger: Calling NavigationService.AddBackEntry / creating journal entries with a CustomContentState subclass not marked [Serializable] (and not implementing ISerializable), especially with NavigationMode.Remember navigation.
Common situations: Custom view-state class missing [Serializable] attribute; CustomContentState added in IProvideCustomContentState implementations; journal persistence paths that require serialization.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- SR.Format(SR.InvalidOperation_MustImplementIPCCSOrHandleNavi…
- SR.InvalidOperation_AddBackEntryNoContent
- SR.InvalidOperation_CannotClearFwdStack
- SR.InvalidOperation_CantChangeJournalOwnership
- SR.InvalidOperation_NoJournal
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/8259d84cc6400adf.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Navigation/NavigationService.cs:3231
// _customContentStateToSave can be preset by AddBackEntry() or FireNavigating().
// If not, try the IProvideCustomContentState callback.
CustomContentState ccs = _customContentStateToSave;
if (ccs == null)
{
IProvideCustomContentState pccs = _bp as IProvideCustomContentState;
if (pccs != null)
{
ccs = pccs.GetContentState();
}
}
if (ccs != null)
{
// Make sure the object is serializable
Type type = ccs.GetType();
if (!type.IsSerializable)
{
throw new SystemException(SR.Format(SR.CustomContentStateMustBeSerializable, type));
}
journalEntry.CustomContentState = ccs;
}
// Info: CustomContentState for the current page in child frames is saved in
// DataStreams.SaveState(). (This requires the IProvideCustomContentState to be implemented.)
// Root Viewer journaling
if (_rootViewerStateToSave != null) // state saved in advance?
{
journalEntry.RootViewerState = _rootViewerStateToSave;
_rootViewerStateToSave = null;
}
else
{
journalEntry.RootViewerState = GetRootViewerState(journalReason);
}
// Set the friendly Name of this JournalEntry, it will be used to displayView on GitHub (pinned to 81131a70a4)