{"record":{"id":"4aec2d07be665661","repo":"xai-org/grok-build","slug":"cancelled-during-ignored-only-copy","errorCode":null,"errorMessage":"cancelled during ignored-only copy","messagePattern":"cancelled during ignored-only copy","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/codegen/xai-fast-worktree/src/api.rs","lineNumber":538,"sourceCode":"\n        let start = std::time::Instant::now();\n        let unignored_paths = crate::copy::collect_unignored_paths(source, num_workers)?;\n\n        let copy_config = ParallelCopyConfig {\n            num_workers,\n            channel_buffer: self.channel_buffer,\n            skip_files: Some(Arc::new(unignored_paths)),\n            respect_gitignore: false,\n            skip_patterns,\n        };\n\n        let copy_result =\n            crate::copy::copy_parallel(source, dest, copy_config, self.cancellation_token.clone())?;\n\n        // `copy_parallel` returns Ok with partial stats on cancellation; surface\n        // it so an interrupted copy isn't treated as success.\n        if self.cancellation_token.is_cancelled() {\n            anyhow::bail!(\"cancelled during ignored-only copy\");\n        }\n\n        tracing::debug!(\n            elapsed = ?start.elapsed(),\n            files = copy_result.stats.files_copied,\n            dirs = copy_result.stats.dirs_created,\n            symlinks = copy_result.stats.symlinks_copied,\n            skipped = copy_result.stats.files_skipped,\n            \"copying ignored files (ignored-only) complete\"\n        );\n\n        Ok(copy_result.stats.into())\n    }\n}\n\n/// Error context attached when worktree creation fails on a full disk. The\n/// pager matches on it, so this constant is the cross-crate contract.\npub const OUT_OF_DISK_CONTEXT: &str = \"not enough free disk space\";","sourceCodeStart":520,"sourceCodeEnd":556,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-fast-worktree/src/api.rs#L520-L556","documentation":"`copy_ignored_only` copies git-ignored files from source to dest in parallel using `copy_parallel`. Since `copy_parallel` returns Ok with partial stats when the cancellation token fires, this function explicitly checks the token afterwards and bails so an interrupted copy is never reported as success. Hitting this error means the copy was cancelled partway through.","triggerScenarios":"Calling `copy_ignored_only` while (or before) the shared `CancellationToken` is cancelled — e.g. the user aborts the operation, a parent task times out, or the token was cancelled earlier and never reset.","commonSituations":"User-initiated cancellation of a session/worktree sync; shutdown or timeout logic cancelling the token mid-copy; reusing a token that was cancelled by a previous failed operation; slow/large ignored-file trees increasing the window for cancellation.","solutions":["Check what cancelled the shared `CancellationToken` (user abort, timeout, upstream failure) before retrying.","Create/obtain a fresh, non-cancelled token (e.g. `CancellationToken::new()` or a child token from an uncancelled parent) and re-run `copy_ignored_only`.","Verify dest state after cancellation — the copy is partial — and either delete the partial dest or make the retry idempotent (copy_parallel overwrites).","If cancellation was unintended, fix the owner of the token (don't cancel a token shared across unrelated operations).","Prefer the structured cancellation result: treat this error as 'operation cancelled', not a copy bug."],"exampleFix":"// before\nlet token = shared_token; // already cancelled by a previous op\napi.copy_ignored_only(&src, &dst, &token)?;\n// after\nlet token = CancellationToken::new(); // fresh token for this operation\nmatch api.copy_ignored_only(&src, &dst, &token) {\n    Err(e) if e.to_string().contains(\"cancelled during ignored-only copy\") => {\n    fs::remove_dir_all(&dst).ok(); // discard partial copy\n    // retry or propagate as Canceled\n    }\n    other => other?,\n}\n","handlingStrategy":"try-catch","validationCode":"// Ensure the token isn't already cancelled before starting.\nif cancellation_token.is_cancelled() {\n    // create a fresh token or abort early instead of a doomed copy\ncancellation_token = CancellationToken::new();\n}","typeGuard":null,"tryCatchPattern":"match api.copy_ignored_only(&src, &dst, &token) {\n    Err(e) if e.to_string().contains(\"cancelled during ignored-only copy\") => {\n    fs::remove_dir_all(&dst).ok(); // clean partial output\n    return Err(OperationCancelled);\n    }\n    r => r?,\n}","preventionTips":["Never share one CancellationToken across unrelated operations","Reset/replace tokens after a cancelled run before reusing them","Keep ignored-file trees small to shrink the cancellation window","After cancellation, always treat dest as partial and clean or reconcile it"],"tags":["cancellation","async","copy","partial-state"],"backgroundTag":"operation-cancelled","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}