{"record":{"id":"f7b26d9a2f7b2ba8","repo":"gitbutlerapp/gitbutler","slug":"change-drop-data-must-specify-the-source-stackid-f7b26d","errorCode":null,"errorMessage":"Change drop data must specify the source stackId","messagePattern":"Change drop data must specify the source stackId","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/src/lib/dragging/dropHandlers/stackDropHandler.ts","lineNumber":102,"sourceCode":"\t\t\t\tif (!outcome.newCommit) {\n\t\t\t\t\tthrow new Error(\"Failed to create a new commit\");\n\t\t\t\t}\n\n\t\t\t\tconst sourceStackId = data.stackId;\n\t\t\t\tconst sourceCommitId = data.selectionId.commitId;\n\t\t\t\tif (sourceStackId) {\n\t\t\t\t\tconst diffSpec = changesToDiffSpec(await data.treeChanges());\n\t\t\t\t\tawait this.macros.moveChangesToNewCommit(\n\t\t\t\t\t\tstack.id,\n\t\t\t\t\t\toutcome.newCommit,\n\t\t\t\t\t\tsourceStackId,\n\t\t\t\t\t\tsourceCommitId,\n\t\t\t\t\t\tbranchName,\n\t\t\t\t\t\tdiffSpec,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Should not happen, but just in case\n\t\t\t\t\tthrow new Error(\"Change drop data must specify the source stackId\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"worktree\": {\n\t\t\t\tconst stack = await this.stackService.newStackMutation({\n\t\t\t\t\tprojectId: this.projectId,\n\t\t\t\t\tbranch: { name: undefined },\n\t\t\t\t});\n\n\t\t\t\tconst changes = await data.treeChanges();\n\t\t\t\tconst assignments = changes\n\t\t\t\t\t.flatMap((c) =>\n\t\t\t\t\t\tthis.uncommittedService.getAssignmentsByPath(data.stackId ?? null, c.path),\n\t\t\t\t\t)\n\t\t\t\t\t.map((h) => ({\n\t\t\t\t\t\thunkHeader: h.hunkHeader,\n\t\t\t\t\t\tpathBytes: h.pathBytes,\n\t\t\t\t\t\ttarget: this.stackTarget(stack.id),","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/apps/desktop/src/lib/dragging/dropHandlers/stackDropHandler.ts#L84-L120","documentation":"Thrown by StackDzHandler.ondropChangeData in stackDropHandler.ts when a change with selectionId.type === \"commit\" is dropped onto a stack dropzone (creating a new stack/commit) but data.stackId is undefined, so moveChangesToNewCommit cannot know which stack the changes come from. acceptsChangeDropData normally rejects this case, making it a defensive 'should not happen' throw.","triggerScenarios":"Dropping FileChangeDropData/FolderChangeDropData with selectionId.type 'commit' and undefined stackId onto a stack header; drop data constructed incompletely or the accepts() filter bypassed (programmatic drop, stale payload).","commonSituations":"Drag started from a UI element that never populated stackId; payload predating a stack deletion/reorder; tests or code dispatching drop events with hand-built ChangeDropData lacking stackId; refactor changing how stackId is set on drop data.","solutions":["Ensure the drag source always sets data.stackId when selectionId.type is 'commit'","Keep acceptsChangeDropData() in the pipeline so drops with undefined stackId are rejected before ondropChangeData","When building drop data in tests or programmatically, include stackId (and selectionId.commitId)","Refresh the UI so drop data references existing stacks"],"exampleFix":"// before: payload missing source stack\nconst data = new FileChangeDropData({ selectionId: { type: 'commit', commitId }, stackId: undefined, ... });\n// after\nconst data = new FileChangeDropData({ selectionId: { type: 'commit', commitId }, stackId: sourceStack.id, ... });","handlingStrategy":"validation","validationCode":"function canDropOnStack(data: unknown): data is ChangeDropData {\n  return (data instanceof FileChangeDropData || data instanceof FolderChangeDropData) &&\n    data.selectionId.type === 'commit' &&\n    typeof data.stackId === 'string';\n}","typeGuard":"function hasSourceStack(d: ChangeDropData): d is ChangeDropData & { stackId: string } {\n  return typeof d.stackId === 'string';\n}","tryCatchPattern":"try {\n  await handler.ondropChangeData(data);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('must specify the source stackId')) {\n    toast.error('Drop data is missing its source stack; refresh and retry');\n  } else throw e;\n}","preventionTips":["Always set stackId on change drop data with selectionId.type 'commit'","Keep acceptsChangeDropData() as the gate before ondropChangeData","Populate complete payloads in tests and programmatic drops","Refresh drag sources after stack deletions or reorders"],"tags":["drag-and-drop","missing-required-field","desktop-app","frontend"],"backgroundTag":"missing-required-argument","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}