different-ai/openwork · error

A valid transferId is required.

Error message

A valid transferId is required.

What it means

desktopTransferKey() validates the transferId supplied by a renderer over IPC before keying an active-transfer map. A valid id must be a non-empty string of at most 128 chars matching /^[a-zA-Z0-9._-]+$/. Anything else throws this error, protecting the Map from untrusted or malformed renderer input.

Solutions

  1. Generate transferId in the renderer as crypto.randomUUID() (matches the allowed charset).
  2. Trim and validate the id client-side before invoking the IPC call.
  3. Ensure input is an object: pass { transferId } rather than the raw string.
  4. Check for version skew — reload/rebuild the renderer so it matches the main-process contract.

Example fix

// before
invoke('desktop:transfer', { transferId: `${file.name} (${i})` });
// after
const transferId = crypto.randomUUID();
invoke('desktop:transfer', { transferId });
Defensive patterns

Strategy: validation

Validate before calling

const TRANSFER_ID_RE = /^[a-zA-Z0-9._-]{1,128}$/;
if (typeof transferId !== 'string' || !TRANSFER_ID_RE.test(transferId.trim())) {
  throw new TypeError('transferId must be 1-128 chars of [a-zA-Z0-9._-]');
}

Type guard

function isValidTransferId(v) {
  return typeof v === 'string' && v.length > 0 && v.length <= 128 && /^[a-zA-Z0-9._-]+$/.test(v);
}

Try / catch

try {
  await runDesktopTransfer(event, input, op);
} catch (err) {
  if (String(err.message) === 'A valid transferId is required.') {
    console.error('Bad transferId from renderer:', input?.transferId);
  } else throw err;
}

Prevention

When it happens

Trigger: Any IPC desktop transfer call (runDesktopTransfer) whose input.transferId is missing, not a string, empty/whitespace, longer than 128 chars, or contains characters outside [a-zA-Z0-9._-] (e.g. spaces, slashes, unicode).

Common situations: Renderer sending undefined transferId after a refactor; generating ids with characters like ':' or '/'; pasting a UUID with braces; corrupted IPC payload from an older renderer bundle.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/f0653843265f98ae. Report an issue: GitHub.

Appendix: source

Thrown at apps/desktop/electron/main.mjs:1078

const browserPanel = createBrowserPanel({
  remoteDebugPort,
  getWindow: () => mainWindow,
  onDeepLink: (urls) => queueDeepLinks(urls),
});

const workspaceStore = createWorkspaceStore({
  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(),
    ]);

View on GitHub (pinned to 2b7df46e8a)