dotnet/wpf · error · InvalidOperationException

Only string and DateTime types are supported for…

Error message

Only string and DateTime types are supported for marshalling to PROPVARIANT.

What it means

When a search host calls IFilter::GetValue on a chunk carrying a value, WPF's IndexingFilterMarshaler converts the .NET object returned by GetValue into a native PROPVARIANT. Only string (VT_LPWSTR) and DateTime (VT_FILETIME) have defined conversions here; any other object type falls into the else branch and throws InvalidOperationException (SR.FilterGetValueMustBeStringOrDateTime).

Solutions

  1. Ensure GetValue only returns string or DateTime; convert other values with ToString() (or DateTime conversion) before exposing them
  2. Wrap the value provider and pre-coerce unsupported types: numbers/bools to string, dates to DateTime
  3. Avoid storing non-string/non-DateTime values in package properties that will be indexed, or ship a custom IFilter that maps them to PROPVARIANT types

Example fix

// before
object value = 42; // int not supported by MarshalPropVariant

// after
object value = 42.ToString(); // string is marshalled as VT_LPWSTR
// or for dates:
object dateValue = ((DateTimeOffset)someDate).UtcDateTime; // DateTime marshalled as VT_FILETIME
Defensive patterns

Strategy: validation

Validate before calling

if (!(value is string) && !(value is DateTime))
{
    value = value?.ToString(); // coerce before the value reaches MarshalPropVariant
}

Type guard

static bool IsFilterValueSupported(object value)
    => value is string || value is DateTime;

Try / catch

try
{
    IntPtr p = filter.GetValue();
}
catch (InvalidOperationException ex)
{
    // value type not marshalable to PROPVARIANT; coerce or skip this property
    log.Warn(ex.Message);
}

Prevention

When it happens

Trigger: GetValue returns an object that is neither string nor DateTime — e.g., an int, double, bool, Guid, or byte[] exposed as a package property — and the marshaler reaches MarshalPropVariant.

Common situations: Indexing an XPS/OPC package whose custom properties contain numeric or boolean values (set via PackageProperties or custom part metadata); a property type changed across versions from string to a typed value; generic object-typed property bags feeding the filter.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/6c1899c9bed42fab. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/IO/Packaging/indexingfiltermarshaler.cs:207

                    v = new PROPVARIANT
                    {
                        vt = VARTYPE.VT_LPSTR
                    };
                    v.union.pszVal = pszVal;
                }
                else if (obj is DateTime)
                {
                    v = new PROPVARIANT
                    {
                        vt = VARTYPE.VT_FILETIME
                    };
                    long longFileTime = ((DateTime)obj).ToFileTime();
                    v.union.filetime.dwLowDateTime = (Int32)longFileTime;
                    v.union.filetime.dwHighDateTime = (Int32)((longFileTime >> 32) & 0xFFFFFFFF);
                }
                else
                {
                    throw new InvalidOperationException(
                        SR.FilterGetValueMustBeStringOrDateTime);
                }

                // allocate an unmanaged PROPVARIANT to return
                pNative = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(PROPVARIANT)));

                // Per MSDN, AllocCoTaskMem never returns null: check for IntPtr.Zero instead.
                Invariant.Assert(pNative != IntPtr.Zero);

                // marshal the managed PROPVARIANT into the unmanaged block and return it
                Marshal.StructureToPtr(v, pNative, false);
            }
            catch
            {
                if (pszVal != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(pszVal);
                }

View on GitHub (pinned to 81131a70a4)