OpenAPITools / OpenAPITools/openapi-generator

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

Open
#22,561 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Issue: Bug
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/ and inspect the built_value model templates handling vars and defaultValue. Reproduce with the supplied OpenAPI spec and dart-dio command, then verify generated code uses the enum constant for enum and const fields while non-enum defaults remain valid string literals and the Dart output compiles.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart
Domain
tooling
Issue type
Bug
Difficulty
2/5
Estimated time
Half a day
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.