peass-ng/PEASS-ng · error · ArgumentException

Can not serialize non-public type {0}.

Error message

Can not serialize non-public type {0}.

What it means

ObjectMemberAccessor's private constructor builds a reflection-based accessor for a type. The check that rejects non-public types is commented out in this vendored copy, so under the original logic ArgumentException('Can not serialize non-public type {0}.') fires when the constructor is given an internal/private type for YAML serialization. The snippet shown is the source region where that guard would execute.

Source

Thrown at winPEAS/winPEASexe/winPEAS/3rdParty/YamlSerializer/ObjectMemberAccessor.cs:46

        /// 指定した型へのアクセス方法を表すインスタンスを返す
        /// キャッシュに存在すればそれを返す
        /// キャッシュに存在しなければ新しく作って返す
        /// 作った物はキャッシュされる
        /// </summary>
        /// <param name="type">クラスまたは構造体を表す型情報</param>
        /// <returns></returns>
        public static ObjectMemberAccessor FindFor(Type type)
        {
            if ( !MemberAccessors.ContainsKey(type) )
                MemberAccessors[type] = new ObjectMemberAccessor(type);
            return MemberAccessors[type];
        }

        private ObjectMemberAccessor(Type type)
        {
            /*
            if ( !TypeUtils.IsPublic(type) )
                throw new ArgumentException(
                    "Can not serialize non-public type {0}.".DoFormat(type.FullName));
            */ 

            // public properties
            foreach ( var p in type.GetProperties(
                    System.Reflection.BindingFlags.Instance | 
                    System.Reflection.BindingFlags.Public | 
                    System.Reflection.BindingFlags.GetProperty) ) {
                var prop = p; // create closures with this local variable
                // not readable or parameters required to access the property
                if ( !prop.CanRead || prop.GetGetMethod(false) == null || prop.GetIndexParameters().Count() != 0 )
                    continue;
                Func<object, object> get = obj => prop.GetValue(obj, EmptyObjectArray);
                Action<object, object> set = null;
                if ( prop.CanWrite && prop.GetSetMethod(false) != null )
                    set = (obj, value) => prop.SetValue(obj, value, EmptyObjectArray);
                RegisterMember(type, prop, prop.PropertyType, get, set);
            }

View on GitHub (pinned to 53fb989abc)

Solutions

  1. Make the type public (or the relevant members public) so the serializer can reflect it.
  2. Use [YamlSerializable]-compatible public DTOs as an intermediary and map from internal types.
  3. If you control the vendored serializer, note the guard is commented out — non-public types now pass through but may fail later on member access.
  4. Add InternalsVisibleTo if the serializer runs in a friend assembly context.

Example fix

// before
internal class Config { public string Name; } // serializer may reject
// after
public class Config { public string Name; }
Defensive patterns

Strategy: type-guard

Validate before calling

if (type != null && !type.IsPublic && !type.IsNestedPublic) throw new ArgumentException(type.FullName + " must be public for YAML serialization");

Type guard

static bool IsYamlSerializable(Type t) => t.IsPublic || t.IsNestedPublic;

Try / catch

try { serializer.Serialize(writer, obj); } catch (ArgumentException ex) when (ex.Message.Contains("non-public")) { mapToPublicDtoAndRetry(); }

Prevention

When it happens

Trigger: Constructing an ObjectMemberAccessor (via the YAML serializer) for a type not visible to the serializer — internal/private classes, or public types in unsigned assemblies without InternalsVisibleTo being reflected over.

Common situations: Serializing internal config/model classes; types marked internal in libraries; generic types instantiated with internal type arguments.

Related errors


AI-assisted analysis of peass-ng/PEASS-ng@53fb989abc (2026-09-02). Data as JSON: /api/errors/1aa37df415775da8. Report an issue: GitHub.