Skip to content

Troubleshooting ​

An error message from fsp is explained, with its fix, in the fespalier-troubleshooting agent skill (skills/README.md). The table below covers the problems that are not a message of fsp itself.

Symptoms ​

SymptomCauseFix
fsp check passes, but lib/app.g.dart is stalefsp check checks the routes but never compares the committed file with what the tree generatesRegenerate and fail on a difference: Failing CI on a stale file
test/widget_test.dart refers to MyApp and flutter analyze failsflutter create wrote it for the MyApp that fsp init replacedDelete it or rewrite it: fsp init
Routes do not animate on go_router 18go_router 18 checks for MaterialApp from package:material_uiAdd a root transition.dart: go_router 18 and Material
"URIs can't use string interpolation"an unescaped $id in an importEscape it: Importing from a $segment folder
"A Timer is still pending" at the end of a testfakes that use Future.delayed under go_router's whole matched stackpumpRouter and currentLocation
a FlutterError that says a deferred page's code is not loadeda widget test's pump never runs loadLibrary()Deferred routes in tests
the app is blank on the web with otel_zoneOtelZone.runGuarded did not run its body on the web before v0.8.1Bump otel_zone to v0.8.1 or later. On an older one, run the body as it is on the web: OpenTelemetry with otel_zone
a test fails with MissingPluginException on connectivity_statusthe test reaches the plugin without FakeConnectivityReconnects
every screen has two Sentry transactionsSentry's own navigator observer runs next to fespalier'sOne transaction per screen
Deep links (or pushRoute) stop opening pages after the app replaced its router (telemetry: true)The replaced router was not disposed: telemetry keeps its provider a platform observer, ahead of the new oneDispose it after the swap, or keep one router: Turning it on
fsp upgrade says this fsp is the one dart run fespalier keepsthe binary is the launcher's cached copy for the version your pubspec.yaml pinsChange the ref: of fespalier and every companion, then flutter pub get: Upgrading fsp
fsp upgrade says it needs curl, or could not look up the latest releasethe lookup uses the system curl and the network (and HTTPS_PROXY)Install curl, set the proxy, or run the install script: Upgrading fsp
fsp upgrade says the download does not match the release's .sha256 or the pinned checksumthe archive is not what the release published, or what its tag pins: a corrupt download, a proxy that rewrites it, or a tampered release; the message names both hashesNothing was changed. Retry; if it repeats, do not install it, and report it at the repository: Upgrading fsp
fsp upgrade says the tag pins no checksums, or pins another version'sthe release's release_checksums.dart is empty or for a different version (a release staged before its pin commit)Wait for the release to be pinned, or install with the script. For a release you staged yourself, FSP_UPGRADE_ALLOW_UNPINNED=1: Upgrading fsp
fsp upgrade says the downloaded fsp says something other than fsp X.Y.Zthe archive holds a binary of another release, or one that cannot run on this machineNothing was changed. Install with the script, or report it: Upgrading fsp
fsp upgrade says it cannot write to the folder fsp is installed inthe binary sits in a folder you cannot write (/usr/local/bin); fsp upgrade never uses sudoInstall into a folder you own with FSP_INSTALL_DIR, first on PATH: Upgrading fsp

Things to know ​

  • Page transitions and Material. Pages render below their layout.dart, so a layout's Scaffold is not their nearest Material during page transitions. Wrap ListTile-heavy pages in Material(type: MaterialType.transparency, …), as products/page.dart does.
  • Optional nullable parameters are query parameters. In a route file, any optional nullable parameter of a primitive type (or of an enum) becomes a query parameter, including one you meant as widget configuration (String? title). Keep such parameters on inner widgets instead of the file's exported one (How parameters are filled).
  • go_router builds the whole matched stack, so /products/abc also loads /products underneath the not-found view.

Known limitations ​

Types are followed through the files fsp reads, not resolved. Since 0.21.0 fsp follows a typedef and an import prefix declared in the app's own files: the file itself, its relative imports and the package: imports of its own package, through exports and show/hide. So ProductView and the Product it names, or m.Product and Product, are one type. Before 0.21.0 they were compared by spelling, and a typedef counted as a different type. Since 0.22.0 it reads the package: imports of the app's path: dependencies the same way, so a typedef or an enum declared in one is followed too: the packages pubspec.yaml lists with a path: under dependencies, dev_dependencies or dependency_overrides (those of pubspec_overrides.yaml when it has that key, as pub reads it), and their own path: dependencies, found from the pubspecs alone. In a pub workspace (an app that says resolution: workspace) it applies the dependency_overrides of the workspace root too, as pub does for every member: those of the root's pubspec.yaml, or of its pubspec_overrides.yaml when that has the key. pub reads resolution: and workspace: from a pubspec_overrides.yaml too, in place of the pubspec's when the file has the key (even with no value: resolution: there makes the app resolve on its own), and since 0.24.1 so does fsp: an app whose pubspec_overrides.yaml alone says resolution: workspace is a member, and a folder above it whose pubspec_overrides.yaml alone has workspace: can be its root. A workspace: with no value, or [], lists no member: that folder is no root, in its pubspec or in its file. The Dart compiler still catches real mismatches in the generated code.

Not followed, so still compared as spelled: a typedef of a hosted, git: or SDK package (one of a path: dependency too, before 0.22.0), a package of a pub workspace that the pubspec names without a path: (shared: ^1.0.0 with resolution: workspace: write shared: {path: ../shared} to have it followed, which pub accepts in a workspace), a package that only another member of the workspace overrides (pub applies a member's dependency_overrides to the whole workspace, and fsp reads those of the app and of the root, not of a sibling member: write them in the root's pubspec.yaml), a generic typedef (typedef Json<T> = Map<String, T>;), a typedef in a part file, and a name that does not start with a capital letter. A hosted package's files are in the pub cache, which only pub get fills, so following them would make the answer depend on it (why). When two types differ and one of their names could not be followed, the four messages that compare types (a parameter against data.dart, against a section's data.dart, a form's return against its input, and an extra that clashes) end by naming those names: found no declaration of `JsonMap` there, so it compares it as spelled.

Still by spelling: a form field's kind (a typedef Email = String; field is a value field, not a text field), the framework types (Ref, BuildContext, RouteScope, ...), and an enum alias that two routes' query parameters spell differently (Cat in one, Category in another), which stays a mismatch for an action's keys. fsp never reads .dart_tool/, pubspec.lock or the pub cache, so fsp check gives the same answer before and after pub get.

Released under the MIT License.