# Engineering Lessons Recurring bugs, surprising library behaviors, and process insights extracted from completed cycles. Newest at the top. Keep entries short — this is for fast scanning at the start of new cycles, not exhaustive history. --- ## L-001 — Dapper `TypeHandler` is bypassed for enum types during read deserialization **Cycle**: 1 (AZ-484) **Discovered by**: integration test failure (`Error parsing column 12 (source=google_maps - String)`); root-caused via web search to long-standing Dapper issue [#259](https://github.com/DapperLib/Dapper/issues/259). **Affects**: Dapper 2.1.35 (and most other versions until the proposed `Settings.PreferTypeHandlersForEnums` opt-in in PR #2200, not yet merged). **What happens** Registering `SqlMapper.AddTypeHandler(new MyEnumHandler())` for an `enum` type — even via `SqlMapper.TypeHandler` — works for **writes** (the handler's `SetValue` is invoked for parameter binding) but is **silently bypassed for reads**. Dapper's IL-emitted deserializer checks `IsEnum` first and falls back to `Enum.TryParse(string, ignoreCase: true)`. **Why this is dangerous** If the enum's wire string happens to match a member name case-insensitively (e.g., `RegionStatus.Failed` ↔ `"failed"`), the bypass goes unnoticed and round-trip works *accidentally*. The bug only surfaces when the wire format diverges from the C# member name (e.g., `TileSource.GoogleMaps` ↔ `"google_maps"` — `Enum.TryParse("google_maps")` does not match `GoogleMaps` because of the underscore). **Recommended approach** - Do **not** rely on `SqlMapper.TypeHandler` for read-side enum mapping unless the wire values match the enum member names case-insensitively. - For enums whose wire format diverges (snake_case, kebab-case, custom IDs), store the entity field as `string` and provide an explicit converter (`*Converter.ToWireValue` / `FromWireValue`) for use at the service-layer boundary. This is what AZ-484 does for `TileEntity.Source` ↔ `TileSourceConverter`. - Unit-test the converter directly. Do not assume that round-tripping through Dapper proves anything for enums. **Detection** - Unit tests of the type handler in isolation will pass even when the handler is bypassed at runtime. - Failure surfaces only at integration-test time when the actual SELECT runs. - If you must keep an enum-typed field, write at minimum one integration test that reads the enum back through Dapper from a real database row. ---