FreakyKit.Forge emits 34 diagnostics across 7 categories. Error-severity diagnostics block source generation entirely for the affected forge class — no partial output is emitted.
| Severity | Info |
| Category | FreakyKit.Forge.Mode |
| Message | Forge class '{0}' uses explicit method selection mode. Only methods decorated with [ForgeMethod] will be treated as forge methods. |
Emitted on the forge class when Mode = ForgeMode.Explicit is set on [Forge]. Informational only — reminds you that unmarked methods will be ignored.
| Severity | Warning |
| Category | FreakyKit.Forge.Mode |
| Message | Method '{0}' in forge class '{1}' is ignored because explicit mode is active. Add [ForgeMethod] to include this method. |
Emitted when a method has the right shape to be a forge method but lacks the [ForgeMethod] attribute in a class using ForgeMode.Explicit. Add [ForgeMethod] to include the method, or remove it if it's intentionally excluded.
[Forge(Mode = ForgeMode.Explicit)]
public static partial class MyForges
{
[ForgeMethod]
public static partial Dest ToDest(Source s); // OK
public static partial Other ToOther(Source s); // FKF002
}| Severity | Warning |
| Category | FreakyKit.Forge.Mode |
| Message | Private method '{0}' in forge class '{1}' is ignored. Set ShouldIncludePrivate = true on [Forge] to include private methods. |
Emitted when a private method has the forge method shape but ShouldIncludePrivate is false (the default). Set ShouldIncludePrivate = true on [Forge] to opt in.
| Severity | Info |
| Category | FreakyKit.Forge.Mode |
| Message | Forge class '{0}' has ShouldIncludePrivate = true. Private forge methods will be included. |
Informational. Emitted on the class when ShouldIncludePrivate = true.
| Severity | Error |
| Category | FreakyKit.Forge.MethodShape |
| Message | Forge method '{0}' must not have an implementation body. Remove the body; the generator will provide it. |
Forge methods must be declaration-only partial methods. The source generator provides the implementation. Remove the body.
// Wrong — has a body
public static partial PersonDto ToDto(Person source)
{
return new PersonDto(); // FKF020
}
// Correct — declaration only
public static partial PersonDto ToDto(Person source);| Severity | Error |
| Category | FreakyKit.Forge.MethodShape |
| Message | Forge method name '{0}' in class '{1}' is used more than once. Forge method names must be unique within a forge class. |
Two or more forge methods in the same class share the same name. Forge method names must be unique within a forge class. Rename one of the methods.
[Forge]
public static partial class MyForges
{
public static partial DtoA ToDest(SourceA source); // FKF030
public static partial DtoB ToDest(SourceB source); // FKF030 — same name
}| Severity | Info |
| Category | FreakyKit.Forge.MethodShape |
| Message | Forge method '{0}' uses update mode. The destination object will be modified in place. |
Emitted when a forge method uses the update mapping shape: void return type with two parameters (source + destination). The destination object's members will be overwritten in place, with no construction or return.
public static partial void Update(Person source, PersonDto existing);
// Generates: existing.Name = source.Name;| Severity | Error |
| Category | FreakyKit.Forge.MethodShape |
| Message | Update forge method '{0}' destination type '{1}' has no settable members. |
The destination type of an update forge method has no settable properties or fields. There is nothing to update.
A member is considered non-settable if it is:
- A property with no setter (get-only)
- A property with an
init-only setter ({ get; init; }) - A
readonlyfield - A
constfield
If every matching destination member falls into one of these categories, FKF041 is emitted.
| Severity | Info |
| Category | FreakyKit.Forge.MethodShape |
| Message | Before hook '{0}' detected for forge method '{1}'. |
A partial method named OnBefore{MethodName} was found in the forge class. It will be called before the mapping assignments.
[Forge]
public static partial class MyForges
{
public static partial PersonDto ToDto(Person source);
static partial void OnBeforeToDto(Person source); // FKF050
}| Severity | Info |
| Category | FreakyKit.Forge.MethodShape |
| Message | After hook '{0}' detected for forge method '{1}'. |
A partial method named OnAfter{MethodName} was found in the forge class. It will be called after the mapping assignments, before the return statement.
[Forge]
public static partial class MyForges
{
public static partial PersonDto ToDto(Person source);
static partial void OnAfterToDto(Person source, PersonDto result); // FKF051
}| Severity | Warning |
| Category | FreakyKit.Forge.MemberDiscovery |
| Message | Field '{0}' on type '{1}' is ignored because ShouldIncludeFields is false. Set ShouldIncludeFields = true on [ForgeMethod] to include fields. |
A public field was found on the source or destination type but excluded from member discovery because ShouldIncludeFields is false (the default). Set ShouldIncludeFields = true on [ForgeMethod] to include fields.
| Severity | Info |
| Category | FreakyKit.Forge.MemberDiscovery |
| Message | Forge method '{0}' has ShouldIncludeFields = true. Fields will be included in member discovery. |
Informational. Emitted when ShouldIncludeFields = true is set on a [ForgeMethod] attribute.
| Severity | Warning |
| Category | FreakyKit.Forge.MemberMatching |
| Message | Destination member '{0}.{1}' has no matching member in source type '{2}'. It will be left at its default value. |
A property (or field) exists on the destination type but no member with a matching name was found on the source type. The member will be left at its default value. This is a warning, not an error — generation proceeds.
Note: Read-only destination members (get-only properties, init-only properties, readonly fields, const fields) are excluded from this check because the generator never assigns them. No FKF100 is emitted for members that cannot be written to.
| Severity | Warning |
| Category | FreakyKit.Forge.MemberMatching |
| Message | Source member '{0}.{1}' has no matching member in destination type '{2}' and will not be mapped. |
A member exists on the source type but the destination type has no corresponding member. The source member is simply not mapped. This is a warning, not an error.
| Severity | Info |
| Category | FreakyKit.Forge.MemberMatching |
| Message | Member '{0}' on type '{1}' is excluded from mapping via [ForgeIgnore]. |
The member is marked with [ForgeIgnore] and will not participate in forge mapping. No FKF100/FKF101 warnings are emitted for ignored members.
Note: This diagnostic is declared and reserved but is not currently emitted by the analyzer or generator. Ignored members are silently excluded. The diagnostic ID is reserved for future verbose output.
public class Source
{
public string Name { get; set; }
[ForgeIgnore] public string InternalId { get; set; } // silently skipped
}| Severity | Info |
| Category | FreakyKit.Forge.MemberMatching |
| Message | Member '{0}' on type '{1}' is mapped to counterpart '{2}' via [ForgeMap]. |
A [ForgeMap] attribute is applied to this member, mapping it to a differently-named member on the counterpart type.
Note: This diagnostic is declared and reserved but is not currently emitted by the analyzer or generator. Custom mappings are applied silently. The diagnostic ID is reserved for future verbose output.
public class Source { [ForgeMap("Name")] public string FirstName { get; set; } }
// Custom mapping applied silently| Severity | Error |
| Category | FreakyKit.Forge.MemberMatching |
| Message | Member '{0}' on type '{1}' maps to '{2}' via [ForgeMap], but no member named '{2}' was found on the counterpart type. |
The [ForgeMap] attribute specifies a target member name that does not exist on the counterpart type. Check the target name for typos.
| Severity | Warning |
| Category | FreakyKit.Forge.MemberMatching |
| Message | Multiple members map to the same target key '{0}'. Member '{1}' on type '{2}' conflicts with a previous mapping. |
Two or more members on the same type map to the same counterpart member name. The later mapping overwrites the earlier one.
public class Source
{
[ForgeMap("Name")] public string First { get; set; }
[ForgeMap("Name")] public string Last { get; set; } // FKF105 — conflicts
}| Severity | Info |
| Category | FreakyKit.Forge.MemberMatching |
| Message | Destination member '{0}' was mapped via flattening to source path '{1}.{2}'. |
The destination member was matched by flattening a nested source property. For example, AddressCity maps to source.Address.City.
Note: This diagnostic is emitted by the generator only, not by the analyzer.
[ForgeMethod(AllowFlattening = true)]
public static partial Dest ToDest(Source source);
// FKF106: AddressCity → Address.City| Severity | Error |
| Category | FreakyKit.Forge.MemberMatching |
| Message | Destination member '{0}.{1}' has no matching member in source type '{2}'. StrictMapping is enabled — all destination members must be mapped. |
Emitted instead of FKF100 when StrictMapping = true on the [ForgeMethod]. Every destination member must have a corresponding source member. This catches mapping drift when destination types gain new members that the source doesn't satisfy.
To fix:
- Add a matching member to the source type
- Exclude the destination member with
[ForgeIgnore] - Remove
StrictMapping = trueto downgrade to a warning
[ForgeMethod(StrictMapping = true)]
public static partial Dest ToDest(Source source);
// FKF110 if Dest has a member not present in Source| Severity | Error |
| Category | FreakyKit.Forge.MemberMatching |
| Message | Source member '{0}.{1}' has no matching member in destination type '{2}'. StrictMapping is enabled — all source members must be consumed or explicitly ignored. |
Emitted instead of FKF101 when StrictMapping = true on the [ForgeMethod]. Every source member must have a corresponding destination member or be excluded with [ForgeIgnore]. This catches mapping drift when source types gain new members that aren't being mapped.
To fix:
- Add a matching member to the destination type
- Exclude the source member with
[ForgeIgnore] - Remove
StrictMapping = trueto downgrade to a warning
[ForgeMethod(StrictMapping = true)]
public static partial Dest ToDest(Source source);
// FKF111 if Source has a member not present in Dest| Severity | Error |
| Category | FreakyKit.Forge.TypeSafety |
| Message | Member '{0}': source type '{1}' is incompatible with destination type '{2}'. No forge conversion is available. |
A source and destination member share a name but have different types, and no forge method, converter, or automatic conversion exists to bridge them. This is an error — generation is blocked.
To fix:
- Provide a forge method that converts between the two types and set
AllowNestedForging = true - Add a
[ForgeConverter]method that bridges the types - Change one of the types to match
- Exclude the mismatched member with
[ForgeIgnore]
public class Source { public int Value { get; set; } }
public class Dest { public string Value { get; set; } } // int vs string — FKF200| Severity | Warning |
| Category | FreakyKit.Forge.TypeSafety |
| Message | Member '{0}': mapping nullable value type '{1}' to non-nullable '{2}' will use .Value which may throw at runtime. |
A Nullable<T> value type is being mapped to its non-nullable counterpart T using .Value. This works but throws InvalidOperationException if the source value is null at runtime.
public class Source { public int? Age { get; set; } }
public class Dest { public int Age { get; set; } }
// Generates: __result.Age = source.Age.Value; // FKF201| Severity | Info |
| Category | FreakyKit.Forge.TypeSafety |
| Message | Member '{0}': nullable mapping applied from '{1}' to '{2}'. |
The source and destination types differ only in nullability. The generator handles this automatically (direct assignment for T → Nullable<T>, .Value for Nullable<T> → T).
| Severity | Info |
| Category | FreakyKit.Forge.TypeSafety |
| Message | Member '{0}': enum cast from '{1}' to '{2}'. |
The source and destination members are different enum types. A direct cast ((DestEnum)source.Value) is generated. This is the default behavior.
| Severity | Info |
| Category | FreakyKit.Forge.TypeSafety |
| Message | Member '{0}': enum name-based mapping from '{1}' to '{2}'. |
The source and destination members are different enum types. A switch expression mapping by member name is generated. Enabled with MappingStrategy = ForgeMapping.ByName.
| Severity | Warning |
| Category | FreakyKit.Forge.TypeSafety |
| Message | Enum member '{0}' in source type '{1}' has no corresponding member in destination type '{2}'. |
A member of the source enum type has no matching member (by name) in the destination enum type. The generated switch expression will throw for this value at runtime.
public enum SourceStatus { Active, Inactive, Pending }
public enum DestStatus { Active, Inactive } // FKF212: Pending is missing| Severity | Info |
| Category | FreakyKit.Forge.TypeSafety |
| Message | Member '{0}': type converter '{1}' was used to convert from '{2}' to '{3}'. |
A method marked with [ForgeConverter] was used to bridge the type mismatch for this member.
[ForgeConverter]
public static string ConvertDateTime(DateTime value) => value.ToString("yyyy-MM-dd");
// FKF220: Birthday converter used from DateTime to string| Severity | Warning |
| Category | FreakyKit.Forge.TypeSafety |
| Message | Method '{0}' is marked with [ForgeConverter] but has an invalid signature: {1}. The converter will be ignored. |
A method marked with [ForgeConverter] does not meet the requirements and will be silently ignored by the generator. This can cause an unexpected FKF200 error when users assume the converter is registered.
A valid converter must be: static, non-void, non-generic, and take exactly one parameter.
// Wrong — two parameters (FKF221)
[ForgeConverter]
public static string ConvertDate(DateTime value, string format) => value.ToString(format);
// Wrong — void return (FKF221)
[ForgeConverter]
public static void ConvertDate(DateTime value) { }
// Correct
[ForgeConverter]
public static string ConvertDate(DateTime value) => value.ToString("yyyy-MM-dd");| Severity | Warning |
| Category | FreakyKit.Forge.Nested |
| Message | Member '{0}': source type '{1}' differs from destination type '{2}'. A forge method exists for this conversion but AllowNestedForging is false. |
A member pair has different types and a forge method exists that could convert between them, but AllowNestedForging is false on the current method. Set AllowNestedForging = true on [ForgeMethod] to enable it. Without it, the member is skipped.
[Forge]
public static partial class MyForges
{
public static partial AddressDto ToAddressDto(Address source);
// FKF300 — forge method exists but AllowNestedForging is false
public static partial PersonDto ToDto(Person source);
// Fix: add [ForgeMethod(AllowNestedForging = true)]
[ForgeMethod(AllowNestedForging = true)]
public static partial PersonDto ToDtoFixed(Person source); // OK
}| Severity | Info |
| Category | FreakyKit.Forge.Nested |
| Message | Member '{0}': collection mapping from '{1}' to '{2}'. |
The source and destination members are both collection types. The generator maps element-by-element using LINQ (.ToList(), .ToArray(), or .Select(x => ...).ToList() for different element types).
| Severity | Error |
| Category | FreakyKit.Forge.Construction |
| Message | Type '{0}' has multiple constructors that are equally viable for forge construction. |
The destination type has multiple public constructors where all parameters can be satisfied from source members. The generator cannot choose between them. Add a parameterless constructor or reduce to a single viable constructor.
| Severity | Error |
| Category | FreakyKit.Forge.Construction |
| Message | Constructor parameter '{0}' on type '{1}' has no matching source member in '{2}'. |
A required constructor parameter on the destination type has no matching source member (by name and type, case-insensitive). The constructor cannot be satisfied.
| Severity | Error |
| Category | FreakyKit.Forge.Construction |
| Message | Type '{0}' has no viable constructor for forge construction. Provide a parameterless constructor or a constructor whose parameters can all be satisfied from source type '{1}'. |
No public constructor on the destination type can be used. Either there are no public constructors at all, or all constructors have parameters that can't be matched from the source type.