Skip to content

[firebase-vscode] SQL Connect uses the first **/firebase.json found, including ones in files.exclude'd folders such as git worktrees, and forgets the panel's pick on reload #11465

Open

Description

@vgerasymenko

[REQUIRED] Environment info

firebase-tools: 15.34.1. Firebase SQL Connect for VS Code 2.4.3 (bundled SQL Connect toolkit 3.4.16), and the current main of firebase-vscode/src/core/config.ts (851baf5).

Platform: Windows 11, VS Code 1.145.2

[REQUIRED] Test case

A workspace folder with firebase.json and dataconnect/ at its root, and git worktrees of the same repository inside that folder, each with its own firebase.json. Ours live in .claude/worktrees/<name>/, where Claude Code creates them. The worktrees' folder is listed in files.exclude and files.watcherExclude.

The extension picks the firebase.json it uses here (config.ts at 851baf5):

  • L330-L331: workspace.findFiles("**/firebase.json", "**/node_modules"). Because an explicit exclude is passed, VS Code does not apply files.exclude (the findFiles docs: "When undefined, default file-excludes (e.g. the files.exclude-setting …) will apply"), so every nested firebase.json is a candidate.
  • L198-L213: with nothing selected, it takes allConfigUris[0]. findFiles does not guarantee any order, so which config wins is arbitrary.
  • L255-L259: a pick in the panel goes into a globalSignal, which lives only in memory (globals.ts L16), so it is lost on every reload.
  • L318-L327: the watcher follows files.watcherExclude, so when the selected config's folder is deleted, onDidDelete never fires and the deleted config stays selected.

By contrast, getConfigPath() (L348-L367) already prefers the workspace root folder that contains a firebase.json.

[REQUIRED] Steps to reproduce

We saw this on two VS Code starts in our repository. We have not reduced it to a fresh repository; these steps are the smallest setup the code above implies.

  1. In a project with firebase.json and dataconnect/ at the root, run git worktree add .worktrees/other.
  2. Add "files.exclude": { "**/.worktrees": true } to the workspace settings.
  3. Open the root folder in VS Code with the extension installed, and let it start the SQL Connect toolkit.
  4. Look at the emulator's command line, e.g. on Windows: Get-CimInstance Win32_Process | Where-Object Name -like 'dataconnect-emulator*' | Select-Object CommandLine.

[REQUIRED] Expected behavior

The toolkit uses the workspace root's firebase.json, or the config picked in the panel, and keeps that pick across reloads. A folder excluded by files.exclude is not a candidate.

[REQUIRED] Actual behavior

On both starts the emulator ran on a worktree, not the root:

dataconnect-emulator-3.4.16.exe --logtostderr -v=2 dev --listen=localhost:50001
  --config_dir=c:\…\.claude\worktrees\<worktree>\dataconnect
  --enable_output_schema_extensions=true --enable_output_generated_sdk=true

Effects:

  • Language features in the root window are served from that worktree's (older) schema.
  • The toolkit regenerated the worktree's SDK in place, about 45 s after start. It changed peerDependencies["firebase-admin"] in both generated package.json files from ^13.4.0 || ^14.0.0 (as firebase-tools 15.34.0 generated them) to ^13.4.0. That left uncommitted changes in a checkout nobody had opened, which blocked removing the worktree until the files were restored.
  • After the worktree folder was deleted, the emulator kept running with the deleted --config_dir until VS Code was restarted.

Possible fixes, in order of preference:

  1. Prefer the firebase.json in the root folder getConfigPath() chooses when one exists.
  2. Honour files.exclude, e.g. by combining its keys with **/node_modules in the exclude glob.
  3. Keep the selected config in workspaceState so a pick survives a reload.

Related: #11363, another report of ours on the same extension.

Activity

  1. vgerasymenko commented on Nov 7, 2026

    @vgerasymenko
    Author

    Two more observations from the same setup (extension 2.4.3, Windows 11, VS Code 1.145.2), measured after a restart on 2026-11-07:

    1. Picking another config in the panel does not move a running toolkit. After the restart the toolkit started on a worktree's firebase.json. We then picked the root firebase.json in the panel. The same emulator process kept the worktree's --config_dir, and the output channel shows no stop or start. toolkit.ts L19-L28 starts the toolkit only when none is running, and no command restarts it. So within a session its folder cannot be changed. Ending the process does not help either: the extension starts no new toolkit until the next reload.

    2. The toolkit and the rest of the extension resolve different folders. The toolkit starts in the selected firebase.json's directory. But the Data Connect configs resolve dataconnect.source against getConfigPath(), which is the workspace root folder (data-connect/config.ts L203-L205, core/config.ts L348-L367). With the toolkit on the nested copy:

    • .firebase/.graphqlrc is written at the root and points at the root's sources. We measured it holding only dataconnect\... paths.
    • The toolkit compiles the nested copy. convertGQLErrorToDiagnostic then pins its errors onto configs.values[0].path, which is the root's files at the nested copy's line numbers.

    Restarting the toolkit when the selected config changes, and resolving both from the same folder, would fix both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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