Skip to content

[BUG][Dart][dart-dio][built_value] Default values for enum fields generated as string literals instead of enum constants #22561

@albe-jj

Description

@albe-jj

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request

Description

When generating Dart code with the dart-dio generator using built_value serialization, fields that are converted to enums (via enum OR const properties) and also have a default value produce invalid Dart code that fails to compile.

The generator:

  1. Correctly creates an EnumClass for fields with enum or const properties
  2. Incorrectly assigns the default value as a string literal instead of the corresponding enum constant

This produces a compilation error:

Error: A value of type 'String' can't be assigned to a variable of type 'DataConvertorTypeEnum?'.
      ..type = 'converter';
               ^

Important findings:

  • The bug occurs with both enum and const properties (both trigger enum generation)
  • Even after removing enum and keeping only const, the generator still creates an EnumClass and still has the bug
  • This commonly occurs when using FastAPI/Pydantic with Literal types that have default values
openapi-generator version
  • openapi-generator-cli version: 7.x (please specify your exact version)
  • Generator: dart-dio
  • Serialization library: built_value
OpenAPI declaration file content or url

Minimal reproduction spec - Case 1: Using enum + default

openapi: 3.1.0
info:
  title: Minimal Reproduction
  version: 1.0.0
paths: {}
components:
  schemas:
    DataConvertor:
      type: object
      required:
        - method
      properties:
        method:
          type: string
        type:
          type: string
          enum:
            - converter
          default: converter

Minimal reproduction spec - Case 2: Using const + default (same bug)

openapi: 3.1.0
info:
  title: Minimal Reproduction
  version: 1.0.0
paths: {}
components:
  schemas:
    DataConvertor:
      type: object
      required:
        - method
      properties:
        method:
          type: string
        type:
          type: string
          const: converter
          default: converter

Both cases produce the same invalid Dart code.

Generation Details
openapi-generator-cli generate \
  -i openapi.yaml \
  -g dart-dio \
  -o ./generated_client \
  --additional-properties=serializationLibrary=built_value
Steps to reproduce
  1. Create an OpenAPI spec with a schema that has a field with either:

    • enum: [single_value] + default: single_value, OR
    • const: single_value + default: single_value
  2. Generate Dart client using dart-dio generator with built_value serialization

  3. Try to compile the generated code with dart compile or flutter build

  4. Observe compilation error in the _defaults method

Actual Output
class DataConvertorTypeEnum extends EnumClass {
  @BuiltValueEnumConst(wireName: r'converter')
  static const DataConvertorTypeEnum converter = _$dataConvertorTypeEnum_converter;

  static Serializer<DataConvertorTypeEnum> get serializer => _$dataConvertorTypeEnumSerializer;

  const DataConvertorTypeEnum._(String name): super(name);

  static BuiltSet<DataConvertorTypeEnum> get values => _$dataConvertorTypeEnumValues;
  static DataConvertorTypeEnum valueOf(String name) => _$dataConvertorTypeEnumValueOf(name);
}

abstract class DataConvertor implements Built<DataConvertor, DataConvertorBuilder> {
  @BuiltValueField(wireName: r'type')
  DataConvertorTypeEnum? get type;
  // enum typeEnum {  converter,  };

  @BuiltValueHook(initializeBuilder: true)
  static void _defaults(DataConvertorBuilder b) => b
      ..type = 'converter';  // ❌ COMPILE ERROR: String cannot be assigned to DataConvertorTypeEnum?
}
Expected Output
class DataConvertorTypeEnum extends EnumClass {
  @BuiltValueEnumConst(wireName: r'converter')
  static const DataConvertorTypeEnum converter = _$dataConvertorTypeEnum_converter;
  // ...
}

abstract class DataConvertor implements Built<DataConvertor, DataConvertorBuilder> {
  @BuiltValueField(wireName: r'type')
  DataConvertorTypeEnum? get type;

  @BuiltValueHook(initializeBuilder: true)
  static void _defaults(DataConvertorBuilder b) => b
      ..type = DataConvertorTypeEnum.converter;  // ✅ CORRECT: Uses enum constant
}
Related issues/PRs
  • Possibly related to discriminator/polymorphism handling
  • May affect other Dart generators with built_value serialization
Suggest a fix

The issue is in the mustache template for built_value model generation. When processing default values, the template should check if the field type is an enum and use the enum constant instead of the string literal.

Location: modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/

Current behavior (pseudo-template):

{{#vars}}
{{#defaultValue}}
..{{name}} = '{{{defaultValue}}}';
{{/defaultValue}}
{{/vars}}

Expected behavior:

{{#vars}}
{{#defaultValue}}
{{#isEnum}}
..{{name}} = {{enumName}}.{{defaultValue}};
{{/isEnum}}
{{^isEnum}}
..{{name}} = '{{{defaultValue}}}';
{{/isEnum}}
{{/defaultValue}}
{{/vars}}

Workaround

Until this is fixed, modify your OpenAPI spec (or the source that generates it) to remove both enum/const AND default from single-value discriminator fields:

Instead of (Pydantic/FastAPI):

type: Literal["converter"] = "converter"

Use:

type: str = "converter"

This generates a plain String field with a string default, which compiles correctly:

@BuiltValueField(wireName: r'type')
String? get type;

static void _defaults(DataConvertorBuilder b) => b
    ..type = 'converter';  // ✅ Valid: String to String?

Trade-off: You lose client-side type validation for these discriminator fields, but server-side validation still works.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions