diff --git a/src/internal/kopia/wrapper_test.go b/src/internal/kopia/wrapper_test.go index 3654d8846..f30bef0c7 100644 --- a/src/internal/kopia/wrapper_test.go +++ b/src/internal/kopia/wrapper_test.go @@ -447,6 +447,22 @@ func (suite *KopiaIntegrationSuite) TestBackupCollections_ReaderError() { assert.False(t, stats.Incomplete) // 5 file and 6 folder entries. assert.Len(t, deets.Details().Entries, 5+6) + + failedPath, err := suite.testPath2.Append(testFileName4, true) + require.NoError(t, err) + + ic := i64counter{} + + _, err = suite.w.RestoreMultipleItems( + suite.ctx, + string(stats.SnapshotID), + []path.Path{failedPath}, + &ic, + ) + // Files that had an error shouldn't make a dir entry in kopia. If they do we + // may run into kopia-assisted incrementals issues because only mod time and + // not file size is checked for StreamingFiles. + assert.ErrorIs(t, err, ErrNotFound, "errored file is restorable") } type backedupFile struct { diff --git a/src/internal/operations/backup.go b/src/internal/operations/backup.go index 6afad0f9a..aeddb86ed 100644 --- a/src/internal/operations/backup.go +++ b/src/internal/operations/backup.go @@ -400,7 +400,32 @@ func consumeBackupDataCollections( ) } - return bu.BackupCollections(ctx, bases, cs, tags, isIncremental) + kopiaStats, deets, itemsSourcedFromBase, err := bu.BackupCollections( + ctx, + bases, + cs, + tags, + isIncremental, + ) + + if kopiaStats.ErrorCount > 0 || kopiaStats.IgnoredErrorCount > 0 { + if err != nil { + err = errors.Wrapf( + err, + "kopia snapshot failed with %v catastrophic errors and %v ignored errors", + kopiaStats.ErrorCount, + kopiaStats.IgnoredErrorCount, + ) + } else { + err = errors.Errorf( + "kopia snapshot failed with %v catastrophic errors and %v ignored errors", + kopiaStats.ErrorCount, + kopiaStats.IgnoredErrorCount, + ) + } + } + + return kopiaStats, deets, itemsSourcedFromBase, err } func matchesReason(reasons []kopia.Reason, p path.Path) bool {