gitbutlerapp/gitbutler · error

textFromToolResult(result)

Error message

textFromToolResult(result)

What it means

Dynamic message: WorkspaceApp.tsx:744 throws new Error(textFromToolResult(result)) when the detail tool call (gitbutler commit or branch details, selected by whether arguments carry commitId or branch) responds with isError. The displayed string is the tool's first text content or "Could not read this workspace." as fallback; the detailRequest token guard keeps stale async results from overwriting a newer selection.

Source

Thrown at packages/but-mcp-app/src/WorkspaceApp.tsx:744

		setDetailLoading(true);
		try {
			const result = await app.callServerTool({
				name:
					nextSelection.kind === "commit" ? "gitbutler_commit_details" : "gitbutler_branch_details",
				arguments:
					nextSelection.kind === "commit"
						? {
								repository: view.repository.path,
								commitId: nextSelection.commit.id,
							}
						: {
								repository: view.repository.path,
								branch: nextSelection.reference.refName.fullName,
							},
			});
			if (request !== detailRequest.current) return;
			if (result.isError) throw new Error(textFromToolResult(result));
			const nextDetail = detailViewFromToolResult(result);
			if (nextDetail === null) throw new Error("The detail result was missing structured data.");
			setDetail(nextDetail);
		} catch (caught) {
			if (request !== detailRequest.current) return;
			setDetailError(caught instanceof Error ? caught.message : "Could not load details.");
		} finally {
			if (request === detailRequest.current) setDetailLoading(false);
		}
	}

	async function handleCopy(value: string) {
		setDetailError(null);
		try {
			await copyText(value);
			setCopied(value);
			window.setTimeout(() => setCopied((current) => (current === value ? null : current)), 1600);
		} catch (caught) {

View on GitHub (pinned to 2497b8007a)

Solutions

  1. Read the surfaced tool text for the exact server-side cause
  2. Re-select the item after repository state settles — the panel reloads details on selection change
  3. Verify the repository path is an open, valid project
  4. Refresh the workspace view to resync commit and branch ids

Example fix

// before
if (result.isError) throw new Error(textFromToolResult(result));

// after — include what was requested so the error is actionable
if (result.isError) {
	const target = nextSelection.kind === "commit" ? nextSelection.commit.id : nextSelection.reference.refName.fullName;
	throw new Error(`Could not load details for ${target}: ${textFromToolResult(result)}`);
}
Defensive patterns

Strategy: validation

Validate before calling

// run before requesting details
if (!selection || !view?.repository.path) return; // nothing selected or no repo: skip the call
const stillInView =
	selection.kind === "commit"
		? view.summary.some((c) => c.id === selection.commit.id)
		: true; // avoid requesting details for commits the current view no longer knows
if (!stillInView) return;

Try / catch

try {
	const result = await app.callServerTool(/* commit or branch detail args */);
	if (request !== detailRequest.current) return; // stale response guard already in place
	if (result.isError) throw new Error(textFromToolResult(result));
} catch (caught) {
	if (request !== detailRequest.current) return;
	setDetailError(caught instanceof Error ? caught.message : "Could not load details.");
}

Prevention

When it happens

Trigger: Requesting details for a commitId that no longer exists (GC'd, rebased away, or from a stale view) or a branch refName that was deleted; repository path invalid; forge or git errors raised server-side while computing details.

Common situations: Selection racing a rebase or branch update; stale workspace view referencing pruned commits; repository moved on disk so the path no longer resolves.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/6ac176a19fd9f6bf. Report an issue: GitHub.