Skip to content

Error: The method 'replace' isn't defined for type 'JsonObject?' when tristate_optionals is enabled #649

@devunt

Description

@devunt

Description

When using Ferry with JsonObject type (from built_value package) and tristate_optionals: true option enabled, the generated serializer code contains calls to .replace() method on JsonObject? fields, but JsonObject doesn't have a replace method.

Important: This error only occurs when tristate_optionals: true is set in the build configuration.

Environment

  • Ferry version: Latest
  • built_value version: 8.11.1
  • Flutter/Dart SDK: Latest stable

Reproduction Steps

  1. Define a GraphQL schema with JSON scalar type:
scalar JSON
  1. Configure build.yaml with type override and tristate_optionals enabled:
targets:
  $default:
    builders:
      ferry_generator|graphql_builder:
        options:
          schema: path/to/schema.graphql
          tristate_optionals: true  # ← This triggers the issue
          type_overrides:
            JSON:
              name: JsonObject
              import: "package:built_value/json_object.dart"
  1. Generate code using build_runner

Generated Code Issue

The generated serializer code produces:

// In schema.schema.gql.dart
case 'params':
  var _$fieldValue = serializers.deserialize(value,
      specifiedType: const FullType(_i1.JsonObject)) as _i1.JsonObject;
  builder.params.replace(_$fieldValue);  // ❌ Error here
  break;

case 'body':
  var _$fieldValue = serializers.deserialize(value,
      specifiedType: const FullType(_i1.JsonObject)) as _i1.JsonObject;
  builder.body.replace(_$fieldValue);  // ❌ Error here
  break;

Error Message

Error: The method 'replace' isn't defined for type 'JsonObject?'.
 - 'JsonObject' is from 'package:built_value/json_object.dart'
Try correcting the name to the name of an existing method, or defining a method named 'replace'.
              builder.params.replace(_$fieldValue);
                             ^^^^^^^

Expected Behavior

The generated code should use proper assignment for JsonObject fields instead of calling .replace() method, similar to how other non-built types are handled:

// Should be:
builder.params = _$fieldValue;
// Instead of:
builder.params.replace(_$fieldValue);

Additional Context

  • The issue does not occur when tristate_optionals: false (or omitted)
  • Looking at the generated .g.dart file, the builder has simple setters for JsonObject fields:
_i1.JsonObject? _params;
_i1.JsonObject? get params => _$this._params;
set params(_i1.JsonObject? params) => _$this._params = params;

The issue seems to be that when tristate_optionals is enabled, the code generator incorrectly treats JsonObject as a built collection type that has a replace method, when it should treat it as a simple value type.

Workaround

Disabling tristate_optionals avoids the issue, but this is not ideal when you need to distinguish between null and absent values in GraphQL inputs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions