different-ai/openwork · error
transferId is already active.
Error message
transferId is already active.
What it means
runDesktopTransfer() keys in-flight transfers by `${event.sender.id}:${transferId}` in activeDesktopTransfers. If a transfer with the same key is already running, it throws this error to prevent concurrent duplicate work on the same sender/transfer pair. The entry is removed in the finally block when the transfer finishes.
Source
Thrown at apps/desktop/electron/main.mjs:1085
app,
defaultDenBaseUrl: DEFAULT_DEN_BASE_URL,
defaultRequireSignin: DEFAULT_DESKTOP_REQUIRE_SIGNIN,
forceRequireSignin: FORCE_DESKTOP_REQUIRE_SIGNIN,
});
const activeDesktopTransfers = new Map();
function desktopTransferKey(event, transferId) {
const normalizedId = typeof transferId === "string" ? transferId.trim() : "";
if (!normalizedId || normalizedId.length > 128 || !/^[a-zA-Z0-9._-]+$/.test(normalizedId)) {
throw new Error("A valid transferId is required.");
}
return `${event.sender.id}:${normalizedId}`;
}
async function runDesktopTransfer(event, input, operation) {
const key = desktopTransferKey(event, input?.transferId);
if (activeDesktopTransfers.has(key)) throw new Error("transferId is already active.");
const controller = new AbortController();
const abort = () => controller.abort();
activeDesktopTransfers.set(key, controller);
event.sender.once("destroyed", abort);
try {
// Both authorities come from app-owned state in userData; workspace-
// writable configuration must never widen where a transfer may write.
const [authorizedRoots, allowedUrlPrefixes] = await Promise.all([
workspaceStore.listLocalWorkspacePaths(),
workspaceStore.listRemoteWorkspaceUrlPrefixes(),
]);
return await operation(input, {
authorizedRoots,
allowedUrlPrefixes,
// App-owned staging keeps in-flight downloads outside every authorized
// workspace root until they complete.
stagingDir: path.join(app.getPath("userData"), "binary-transfers"),
fetcher: electronNet.fetch,View on GitHub (pinned to 2b7df46e8a)
Solutions
- Use a fresh unique transferId for each new operation instead of reusing one.
- Wait for the first transfer's completion before retrying; disable the triggering button while pending.
- If a transfer is stuck, restart the renderer/webContents (sender destruction aborts and clears the key).
- Add renderer-side state so an already-active transfer shows progress instead of re-invoking.
Example fix
// before
await invoke('desktop:transfer', { transferId: 'export' }); // second call throws
// after
const transferId = crypto.randomUUID(); // unique per attempt
await invoke('desktop:transfer', { transferId }); Defensive patterns
Strategy: retry
Validate before calling
// track in-flight ids renderer-side before re-invoking const inFlight = new Set(); if (inFlight.has(transferId)) return; // skip duplicate invocation
Try / catch
try {
await invoke('desktop:transfer', { transferId });
} catch (err) {
if (String(err.message) === 'transferId is already active.') {
await new Promise(r => setTimeout(r, 250)); // then retry with a NEW transferId
} else throw err;
} Prevention
- Issue a fresh transferId per operation attempt.
- Disable triggering UI while a transfer is pending.
- Always await the IPC result before allowing retries.
- Avoid StrictMode double-invocation of transfer effects (guard with a ref).
When it happens
Trigger: An IPC transfer call arrives while a previous call with the same sender id and transferId is still pending — e.g. double-click retry, renderer re-issuing after a slow response, or a stale transfer that never completed (aborts only fire on sender destruction).
Common situations: Users clicking a download/export button twice; the renderer not awaiting the first result before retrying; a hung operation never settling so the key stays in the map; React StrictMode double-invocation of effects.
Related errors
- A valid transferId is required.
- Desktop integration is disabled for test profiles.
- Could not start OpenWork UI control bridge.
- Electron desktop helper is unavailable: ${command}
- Electron desktop helper is unavailable: ${prop}
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/3782d66616f8a2fd.
Report an issue: GitHub.