tinyhumansai/openhuman · warning

worktreeApi.remove: path is required

Error message

worktreeApi.remove: path is required

What it means

A client-side precondition guard in worktreeApi.remove(): trims path and throws before the 'openhuman.worktree_remove' RPC when empty. Unlike status/diff this is a destructive action gated behind a confirm prompt; an empty path here means the remove flow was triggered without a target.

Source

Thrown at app/src/services/api/worktreeApi.ts:84

  /** Fetch a human-readable `git diff HEAD --stat` (plus untracked files). */
  diff: async (path: string): Promise<string> => {
    if (!path.trim()) throw new Error('worktreeApi.diff: path is required');
    log('diff path=%s', path);
    const res = await callCoreRpc<{ summary: string }>({
      method: 'openhuman.worktree_diff',
      params: { path },
    });
    return res.summary;
  },

  /**
   * Remove a worktree checkout. The core refuses a dirty worktree unless
   * `force` is `true`, so a clean worktree removes silently while a dirty one
   * rejects (the caller surfaces a confirm prompt and retries with force).
   */
  remove: async (path: string, force = false): Promise<boolean> => {
    if (!path.trim()) throw new Error('worktreeApi.remove: path is required');
    log('remove path=%s force=%s', path, force);
    const res = await callCoreRpc<{ removed: boolean }>({
      method: 'openhuman.worktree_remove',
      params: { path, force },
    });
    return res.removed;
  },
};

View on GitHub (pinned to a221052e0d)

Solutions

  1. Close or disable the confirm dialog when the target path becomes empty
  2. Capture the path at dialog-open time and re-validate on submit: if (!path.trim()) return;
  3. Clear any pending remove intent when selection resets
  4. Add a defensive early return in the submit handler rather than relying on the throw

Example fix

// before
onConfirm={() => worktreeApi.remove(targetPath, force)}

// after
onConfirm={() => {
  if (!targetPath.trim()) { setDialogOpen(false); return; }
  worktreeApi.remove(targetPath, force);
}}
Defensive patterns

Strategy: validation

Validate before calling

// Re-validate at confirm time — selection may have changed since the dialog opened
const target = pendingRemovePath?.trim();
if (!target) { closeDialog(); return; }
await worktreeApi.remove(target, force);

Prevention

When it happens

Trigger: A remove/confirm dialog whose submit handler reads an empty selectedPath (selection cleared while the dialog was open, or the dialog opened from a context menu with no row); a default parameter path of '' reaching the call.

Common situations: Confirm dialog outliving the selection (user deselects or the list refreshes while dialog open); keyboard-triggered remove with no focused row; race between list refetch resetting selection and the user clicking Remove.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/b62d96f895d82a7c. Report an issue: GitHub.