gitbutlerapp/gitbutler · error
Can't receive a change without it's source or commit
Error message
Can't receive a change without it's source or commit
What it means
Thrown by UncommitDzHandler.ondrop in commitDropHandler.ts when a HunkDropDataV3 payload that is NOT uncommitted (i.e. it belongs to a commit) lacks data.stackId or data.commitId. Uncommitting a hunk requires knowing which stack and commit it is being moved out of, so the handler refuses to proceed.
Solutions
- Make sure the hunk drag source sets stackId and commitId whenever the hunk belongs to a commit (uncommitted=false)
- Check that the dropzone's accepts() rejects hunks without commitId/stackId so ondrop never sees them
- Refresh the commit list so ids reference live commits, not replaced ones
- In tests or programmatic drops, supply both stackId and commitId in HunkDropDataV3
Example fix
// before
const hunk = new HunkDropDataV3({ change, hunk, uncommitted: false, stackId: undefined, commitId: undefined });
// after
const hunk = new HunkDropDataV3({ change, hunk, uncommitted: false, stackId: sourceStack.id, commitId: commit.id }); Defensive patterns
Strategy: type-guard
Validate before calling
function canUncommitHunk(data: unknown): data is HunkDropDataV3 {
return data instanceof HunkDropDataV3 &&
!data.uncommitted && !!data.stackId && !!data.commitId;
} Type guard
function hasHunkSource(d: HunkDropDataV3): d is HunkDropDataV3 & { stackId: string; commitId: string } {
return !d.uncommitted && typeof d.stackId === 'string' && typeof d.commitId === 'string';
} Try / catch
try {
await handler.ondrop(hunkData);
} catch (e) {
if (e instanceof Error && e.message.includes("without it's source or commit")) {
toast.error('Cannot uncommit: hunk source stack/commit is unknown');
} else throw e;
} Prevention
- Set stackId and commitId on every hunk payload created from a commit
- Mirror the handler's accepts() checks at the drag source
- Avoid reusing stale payloads after commit replacements
- Test hunk drop flows with committed and uncommitted variants
When it happens
Trigger: Dropping a HunkDropDataV3 with uncommitted=false but undefined stackId or commitId onto the uncommit dropzone; the accepts() guard (which checks uncommitted, commitId and stackId) was bypassed or the payload was built incompletely.
Common situations: A hunk dragged from a stale commit list where the commit has since been replaced (replacedCommits) leaving dangling ids; hunk drop data constructed by tests or code paths that never set commitId; serialization losing stackId/commitId fields.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Change drop data must specify the source stackId
- Could not find selected project
- Could not find selected project
- Could not find selected project
- Failed to create a new commit
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/6be13f62498cb3f8.
Report an issue: GitHub.
Appendix: source
Thrown at apps/desktop/src/lib/dragging/dropHandlers/commitDropHandler.ts:275
// Update the project state to point to the new commit if needed.
updateUiState(this.uiState, stackId, commitId, workspace.replacedCommits);
},
);
} else {
throw new Error("Change drop data must specify the source stackId");
}
break;
}
case "branch":
console.warn("Moving a branch into a commit is an invalid operation");
break;
case "worktree":
console.warn("Moving a branch into a commit is an invalid operation");
break;
}
} else {
if (!(data.stackId && data.commitId)) {
throw new Error("Can't receive a change without it's source or commit");
}
const previousPathBytes =
data.change.status.type === "Rename" ? data.change.status.subject.previousPathBytes : null;
const sourceStackId = data.stackId;
const sourceCommitId = data.commitId;
await withStackBusy(
this.uiState,
this.projectId,
{ commitId: sourceCommitId, stackIds: [sourceStackId] },
async () => {
const { workspace } = await this.stackService.uncommitChanges({
projectId: this.projectId,
stackId: sourceStackId,
commitId: sourceCommitId,
changes: [
{View on GitHub (pinned to 58e5313667)