flutter_showcaseview icon indicating copy to clipboard operation
flutter_showcaseview copied to clipboard

'controller != null' error

Open basvdijk opened this issue 2 months ago β€’ 8 comments

Describe the bug

With the new structure in v5 I get these kind of errors now and then

════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown building Expanded(flex: 1):
Please register [ShowcaseView] first by calling [ShowcaseView.register()]
Failed assertion: line 177 pos 7: 'controller != null'

This is probably because there seems to be no way to detect if the controller is loaded. So it happens that the guidedtour starts when the showcaseview does not have its controller ready.

Maybe the register function should be async or have a callback when ready so you know it is safe to start the tour.

To Reproduce Steps to reproduce the behavior:

  @override
  void initState() {
    super.initState();

    ShowcaseView.register(
      disableMovingAnimation: true,
      onFinish: () {
        guidedTourCompleter.complete();
      },
    );

    WidgetsBinding.instance.addPostFrameCallback((_) {
      startGuidedTour();
    });
  }

basvdijk avatar Nov 13 '25 14:11 basvdijk

Hey @basvdijk

Could you please share a complete, minimal code snippet that reproduces this issue? I tested the code you provided inside the package’s example app, but I wasn’t able to trigger the same behaviour.

vasu-nageshri avatar Nov 14 '25 05:11 vasu-nageshri

@vasu-nageshri that is a bit of a problem because it is triggered when navigating between views or have popup dialogs. I will see what I can do. Please not that this does not happen when I use the "old style" Where you wrap your entire build tree.

basvdijk avatar Nov 14 '25 10:11 basvdijk

Hi @basvdijk ,

I tested this using the code from the following gist:

πŸ”— Gist: Example code

I tried it specifically during the pop-up flow, and everything is working correctly on my end in the example setup.

To help identify the issue, could you please share the exact part of your implementation where it’s breaking?
A small reproducible snippet or the widget tree would be really helpful.

Thanks a lot!

vasu-nageshri avatar Nov 17 '25 10:11 vasu-nageshri

@vasu-nageshri The issue is that I can't share my code since it is part of bigger project. So I need to see if I can subtract a part which has the same bug. This will take quite some time.

basvdijk avatar Nov 20 '25 21:11 basvdijk

I want to add that the same thing happens to me. You can have a list of objects where the first object is a ShowCase. Then, you have another route with a tutorial as well. You switch to that one and come back and it happens

StevenMaMei avatar Dec 01 '25 04:12 StevenMaMei

@StevenMaMei, Could you please provide a minimal code sample to reproduce the issue so we can investigate and fix it if needed?

vasu-nageshri avatar Dec 02 '25 12:12 vasu-nageshri

@vasu-nageshri I’m experiencing this same issue as well. It’s inconsistent and difficult to reproduce, but it does happen occasionally. Unfortunately, I can’t determine the exact cause β€” I’m not unregistering the instance anywhere, yet the problem still occurs.

Below is a simplified version of my code (from a much larger project). Please note: openFeatureTourBottomSheet() simply opens a bottom sheet where the user can either start the showcase tour by calling ShowcaseView.get().startShowCase([showCaseKey]); or skip it entirely by popping the sheet Navigator.of(context).pop();


final homeViewModelProvider = Provider<HomeViewModel>((ref) => HomeViewModel());

class HomeViewModel {
  bool isGuestUser() => false;
  Future<void> authenticate() async {}
  Future<void> openFeature(BuildContext context) async {}
}

class HomeScreenBodyV2 extends ConsumerStatefulWidget {
  const HomeScreenBodyV2({super.key});

  @override
  ConsumerState<HomeScreenBodyV2> createState() => _HomeScreenBodyV2State();
}

class _HomeScreenBodyV2State extends ConsumerState<HomeScreenBodyV2> {
  final _refreshController = RefreshController();
  final featureShowcaseKey = GlobalKey();

  @override
  void initState() {
    super.initState();

    ShowcaseView.register(blurValue: 1);

    WidgetsBinding.instance.addPostFrameCallback((_) {
      _init();
    });
  }

  Future<void> _init() async {
    await Future.delayed(const Duration(milliseconds: 300));
    openFeatureTourBottomSheet();
  }

  @override
  Widget build(BuildContext context) {
    final vm = ref.read(homeViewModelProvider);

    return Scaffold(
      appBar: AppBar(title: const Text("Showcase Test Example")),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          Showcase(
            key: featureShowcaseKey,
            title: "New Feature",
            description: "Tap to open this new feature.",
            targetPadding: const EdgeInsets.all(8),
            targetBorderRadius: BorderRadius.circular(50),
            overlayColor: Colors.black,
            overlayOpacity: 0.7,
            showArrow: true,
            disposeOnTap: true,
            onTargetClick: () async {
              ShowcaseView.get().dismiss();
              await vm.openFeature(context);
            },
            child: const FloatingActionButton(
              onPressed: null,
              child: Icon(Icons.star),
            ),
          ),
        ],
      ),
      body: const Center(
        child: Text("Content Here"),
      ),
    );
  }
}

AliaaIbrahemAhmed avatar Dec 09 '25 00:12 AliaaIbrahemAhmed

Hi @AliaaIbrahemAhmed,

I am unable to reproduce the issue you mentioned. I tried running the code you provided, and it works correctly on my end. I’ve attached a screen recording for your reference.

So far, I still cannot reproduce the issue reported by you and @basvdijk :)

https://github.com/user-attachments/assets/8bd3df26-a790-4944-bac8-829cf8d86c00

vasu-nageshri avatar Dec 10 '25 09:12 vasu-nageshri