Skip to content

coreapp-packaged-indexing-diagnostics-probe's --runMaintenanceAction always throws: the preload has no ipcRenderer.invoke #1775

Description

@TalexDreamSoul

Found by trying to use it. --runMaintenanceAction scan|reconcile|reset cannot work against the current preload, and fails with the probe's own "unavailable" error rather than anything that points at the cause.

The mismatch

coreapp-packaged-indexing-diagnostics-probe.ts:runMaintenanceActionExpression builds:

const invoke = window.electron?.ipcRenderer?.invoke?.bind(window.electron.ipcRenderer)
if (!invoke) throw new Error('window.electron.ipcRenderer.invoke is unavailable')
return await invoke('app:indexed-source:scan', { sourceId, reason: 'manual-rebuild' })

The preload exposes no such method. apps/core-app/src/preload/index.d.ts:14-18:

ipcRenderer: {
  send: (channel: string, ...args: unknown[]) => void
  on: (channel: string, listener: ) => () => void
  removeListener: (channel: string, listener: ) => void
}

Confirmed at runtime, not only from the declaration. Attaching over CDP to a running CoreApp and reading the bridge from both windows:

{"cls":"MacIntel core-box","electron":["ipcRenderer","process"],"ipcKeys":["send","on","removeListener"]}
{"cls":"MacIntel",         "electron":["ipcRenderer","process"],"ipcKeys":["send","on","removeListener"]}

window.electron is present; invoke is not, on either window.

Why it drifted

The preload says so itself (index.ts:166-169):

A narrow replacement for @electron-toolkit/preload's electronAPI. That helper bridges send/on/once/invoke/sendSync/removeAllListeners for any channel name…

So the surface was deliberately narrowed to three methods over an allowlist (assertBridgedChannel, index.ts:161-164). The probe was written against the wide toolkit surface and never updated. Nothing failed at build time because the expression is a string evaluated in the renderer — there is no type checking across that boundary, which is also why a .d.ts that never had invoke did not catch it.

Consequences

  • The three maintenance actions are unreachable. Anyone using the probe to drive a scan gets window.electron.ipcRenderer.invoke is unavailable, which reads like an environment problem rather than a surface mismatch.
  • This is on the path [release/database] Prove default-on search-index split in an isolated CoreApp profile #1748 needs: triggering a file-provider scan against a disposable profile is exactly what --runMaintenanceAction scan is for.
  • assertBridgedChannel means even a send-based rewrite needs app:indexed-source:scan on BRIDGED_IPC_CHANNELS, and a send has no reply — so the probe would also need a matching on for the result. It is not a one-word substitution.

Suggested direction

Either re-expose a narrow invoke restricted to the same allowlist (keeps the request/response shape the probes want), or convert the three actions to send + on and add the channels to the allowlist. The first is smaller; the second keeps the preload's current no-invoke posture.

Whichever way, the probe's inline expression should be typed against BridgedElectronAPI rather than written free-hand, or the next narrowing breaks it the same silent way.

Verification

macOS, dev build launched from the repo root with an isolated userDataDir, CDP attached on 9333, bridge read with Runtime.evaluate. The .d.ts and preload source quoted above are from origin/master.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions