Can we access your project?
Current Behavior
As per the title of the issue invoking a method on a Custom Interface instance stored in a library's App State does not unbox the Enum return type — result is treated as an opaque Custom Interface value instead of the native Enum.
A dependency library project exposes a Custom Code File defining a plain Dart class (e.g. LocationService), whose methods have properly typed async signatures returning a FlutterFlow-native Enum defined in the same library project, e.g.:
Future<LocationPermissionState> getPermissionState() async {
...
}
LocationPermissionState is a real FlutterFlow Enum (created through the Enum editor / Data Types, not just a raw Dart enum), with values granted, denied, permanentlyDenied, serviceDisabled.
An instance of LocationService is held in the library's App State, declared with type Custom Class (Custom Interface), e.g.:
identifier:
name: locationService
dataType:
scalarType: CustomClass
subType:
customInterfaceIdentifier:
name: LocationService
uri: <key>
When invoking getPermissionState() on this App State instance from the visual Action Editor ("Invoke Method" action on a Custom Interface object), the generated action definition looks like this:
outputVariableName: locationPermissionResponse
key: h155kw9p
customInterfaceMethodCall:
interfaceInstance:
source: LOCAL_STATE
baseVariable:
localState:
fieldIdentifier:
name: locationService
stateVariableType: APP_STATE
methodIdentifier:
name: getPermissionState
parameterValues: {}
Note that, unlike a Custom Action definition, this customInterfaceMethodCall block carries no returnParameter/dataType at all. The action's output (locationPermissionResponse) is not typed as the native LocationPermissionState Enum anywhere in the project schema.
The practical consequence shows up as soon as you try to branch on the result. Comparing the output against the enum's own values does not use FlutterFlow's native ENUMS variable source (the one used for ordinary Enum comparisons elsewhere in the project). Instead, the condition editor generates a comparison against the enum treated as if it were itself another Custom Interface, exposing its values as static getters:
condition:
variable:
source: FUNCTION_CALL
functionCall:
values:
- variable:
source: LOCAL_STATE
baseVariable:
localState:
fieldIdentifier:
name: locationPermissionState
stateVariableType: WIDGET_CLASS_STATE
- variable:
source: CUSTOM_INTERFACE_STATIC
baseVariable:
customInterfaceStatic:
customInterfaceIdentifier:
name: LocationPermissionState
getterIdentifier:
name: granted
parameterValues: {}
condition:
relation: EQUAL_TO
So a value that is, at the Dart level, a proper native Enum (LocationPermissionState.granted) ends up being represented and compared in the project schema as a CUSTOM_INTERFACE_STATIC getter lookup on a pseudo-interface named after the enum, not as an ENUMS variable. In the Action/Condition Editor UI this surfaces as the result of the method call being offered as a generic "Custom Class" type rather than being recognized and selectable as the actual LocationPermissionState Enum (no native enum-value dropdown, no direct ENUMS comparison option, no direct binding to widgets/App State fields typed as that Enum).
Expected Behavior
When a method exposed through a Custom Interface (a class living in a Custom Code File) is declared with a return type that is a real FlutterFlow Enum (or Data Type) — not dynamic, not a raw untyped value — invoking that method from the Action Editor should unbox the result as that native Enum type:
- The
outputVariableName of the customInterfaceMethodCall action should carry a returnParameter/dataType of scalarType: Enum with the correct enumIdentifier, exactly as a Custom Action's returnParameter does.
- Subsequent conditions/comparisons against that output should be able to use the native
ENUMS variable source and the standard enum-value picker, instead of being forced into a synthetic CUSTOM_INTERFACE_STATIC getter-based comparison.
- The output should be directly assignable to any Page/Component/App State field typed as that same Enum, the same way a Custom Action's Enum return value is.
In short: FlutterFlow already knows how to fully type an Enum return value coming from a Custom Action (see returnParameter.dataType.scalarType: Enum + subType.enumIdentifier). A method call on a Custom Interface instance whose underlying Dart signature returns that same Enum type should benefit from the same typing, instead of degrading to an opaque Custom Class result.
Steps to Reproduce
- In a Library project, create an Enum, e.g.
MyEnum with a couple of values (valueA, valueB).
- In the same project, add a Custom Code File (Custom Code → Files → Add) defining a plain Dart class with an async method returning that Enum, e.g.:
class MyService {
static final MyService _instance = MyService._internal();
factory MyService() => _instance;
MyService._internal();
Future<MyEnum> getState() async {
return MyEnum.valueA;
}
}
- Add an App State field of type
Custom Class, pointing to MyService as its Custom Interface.
- On a page/component action chain (
ON_TAP or similar), add an "Invoke Method" action targeting that App State instance, calling getState(), and store the output in a variable.
- Try to use that output:
- a) Attempt to set another Enum-typed App State/Page State field directly from this output.
- b) Attempt to build a Condition comparing this output against
MyEnum.valueA using the standard Enum comparison / ENUMS picker.
Observed: neither (a) nor (b) is offered as a direct/native Enum interaction. The output is only usable as a generic Custom Class value; comparisons against enum values must go through a CUSTOM_INTERFACE_STATIC static-getter comparison (selecting the Enum itself as if it were a Custom Interface class), not the native Enum comparison path.
Expected: the output of the method call should be recognized and offered as a native MyEnum value throughout the Action/Condition Editor, since the Dart method signature already declares that return type unambiguously (Future<MyEnum>).
Reproducible from Blank
Bug Report Code (Required)
ITFfksrl25NOseEA0a6JccdojSosJVscTYMvjuphcx4cC73mP4ktd+D4Q0NKTu7heEFUAWGj+DkdpejFj+LDNfo7H06YQaY70JVAaBbNQme5MpCQPZOaWX9QL/pWGEyX07eg2yJ+BMx2ZVYH7U+lNq3qNleeY8aSfxBlZ7vfcPo=
Visual documentation
Additional context
- Workaround currently in use: wrap the method call in a proper Custom Action (
Future<MyEnum> getState() async { return await MyService().getState(); }) with an explicit returnParameter.dataType.scalarType: Enum pointing at MyEnum. This does correctly unbox the Enum and enables native Enum comparisons/assignments downstream.
- That workaround, however, surfaced a second, related bug: when the Custom Action needs to live in the consumer project (rather than in the library that owns the enum) and its
returnParameter references the library's Enum cross-project (subType.enumIdentifier.projectId: <library-project-id>), saving the Custom Action fails with "Unable to process return parameter" (filed separately). The only working configuration found so far is defining the wrapper Custom Action inside the library project itself, where the Enum reference is local (no projectId qualifier needed).
- This suggests the underlying gap is broader than just the Custom Action save error: FlutterFlow's Custom Interface method-call mechanism does not carry return-type metadata the way Custom Actions/Functions do, so any Enum (or Data Type) returned by a Custom Interface method is invisible to the rest of the visual builder's type system unless manually re-wrapped in a properly-typed Custom Action.
Environment
- FlutterFlow version: v7.0.32
- Platform: MacOS app
- Browser name and version:
- Operating system and version affected: Sequoia 15.7.3
Additional Information
No response
Can we access your project?
Current Behavior
As per the title of the issue invoking a method on a Custom Interface instance stored in a library's App State does not unbox the Enum return type — result is treated as an opaque Custom Interface value instead of the native Enum.
A dependency library project exposes a Custom Code File defining a plain Dart class (e.g.
LocationService), whose methods have properly typed async signatures returning a FlutterFlow-native Enum defined in the same library project, e.g.:LocationPermissionStateis a real FlutterFlow Enum (created through the Enum editor / Data Types, not just a raw Dart enum), with valuesgranted,denied,permanentlyDenied,serviceDisabled.An instance of
LocationServiceis held in the library's App State, declared with typeCustom Class(Custom Interface), e.g.:When invoking
getPermissionState()on this App State instance from the visual Action Editor ("Invoke Method" action on a Custom Interface object), the generated action definition looks like this:Note that, unlike a Custom Action definition, this
customInterfaceMethodCallblock carries noreturnParameter/dataTypeat all. The action's output (locationPermissionResponse) is not typed as the nativeLocationPermissionStateEnum anywhere in the project schema.The practical consequence shows up as soon as you try to branch on the result. Comparing the output against the enum's own values does not use FlutterFlow's native
ENUMSvariable source (the one used for ordinary Enum comparisons elsewhere in the project). Instead, the condition editor generates a comparison against the enum treated as if it were itself another Custom Interface, exposing its values as static getters:So a value that is, at the Dart level, a proper native Enum (
LocationPermissionState.granted) ends up being represented and compared in the project schema as aCUSTOM_INTERFACE_STATICgetter lookup on a pseudo-interface named after the enum, not as anENUMSvariable. In the Action/Condition Editor UI this surfaces as the result of the method call being offered as a generic "Custom Class" type rather than being recognized and selectable as the actualLocationPermissionStateEnum (no native enum-value dropdown, no directENUMScomparison option, no direct binding to widgets/App State fields typed as that Enum).Expected Behavior
When a method exposed through a Custom Interface (a class living in a Custom Code File) is declared with a return type that is a real FlutterFlow Enum (or Data Type) — not
dynamic, not a raw untyped value — invoking that method from the Action Editor should unbox the result as that native Enum type:outputVariableNameof thecustomInterfaceMethodCallaction should carry areturnParameter/dataTypeofscalarType: Enumwith the correctenumIdentifier, exactly as a Custom Action'sreturnParameterdoes.ENUMSvariable source and the standard enum-value picker, instead of being forced into a syntheticCUSTOM_INTERFACE_STATICgetter-based comparison.In short: FlutterFlow already knows how to fully type an Enum return value coming from a Custom Action (see
returnParameter.dataType.scalarType: Enum+subType.enumIdentifier). A method call on a Custom Interface instance whose underlying Dart signature returns that same Enum type should benefit from the same typing, instead of degrading to an opaque Custom Class result.Steps to Reproduce
MyEnumwith a couple of values (valueA,valueB).Custom Class, pointing toMyServiceas its Custom Interface.ON_TAPor similar), add an "Invoke Method" action targeting that App State instance, callinggetState(), and store the output in a variable.MyEnum.valueAusing the standard Enum comparison /ENUMSpicker.Observed: neither (a) nor (b) is offered as a direct/native Enum interaction. The output is only usable as a generic Custom Class value; comparisons against enum values must go through a
CUSTOM_INTERFACE_STATICstatic-getter comparison (selecting the Enum itself as if it were a Custom Interface class), not the native Enum comparison path.Expected: the output of the method call should be recognized and offered as a native
MyEnumvalue throughout the Action/Condition Editor, since the Dart method signature already declares that return type unambiguously (Future<MyEnum>).Reproducible from Blank
Bug Report Code (Required)
ITFfksrl25NOseEA0a6JccdojSosJVscTYMvjuphcx4cC73mP4ktd+D4Q0NKTu7heEFUAWGj+DkdpejFj+LDNfo7H06YQaY70JVAaBbNQme5MpCQPZOaWX9QL/pWGEyX07eg2yJ+BMx2ZVYH7U+lNq3qNleeY8aSfxBlZ7vfcPo=
Visual documentation
Additional context
Future<MyEnum> getState() async { return await MyService().getState(); }) with an explicitreturnParameter.dataType.scalarType: Enumpointing atMyEnum. This does correctly unbox the Enum and enables native Enum comparisons/assignments downstream.returnParameterreferences the library's Enum cross-project (subType.enumIdentifier.projectId: <library-project-id>), saving the Custom Action fails with "Unable to process return parameter" (filed separately). The only working configuration found so far is defining the wrapper Custom Action inside the library project itself, where the Enum reference is local (noprojectIdqualifier needed).Environment
Additional Information
No response