fix: improve error handling when packfile cannot be read (fixes #1163)#2295
Conversation
FileSystem.read() silently returns null on errors (including ERR_FS_FILE_TOO_LARGE). In GitPackIndex.readSlice(), the null check tested the Promise object (always truthy) instead of the resolved value, causing a confusing TypeError on .slice(null). - Await the promise before null-checking in readSlice() - Add null check in readObjectPacked after resolving pack data - Clear cached promise on failure to allow retry on transient errors - Add test verifying descriptive InternalError on missing packfile
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe changes add defensive guards and consolidate async pack loading to prevent operations on a missing packfile, plus a test that asserts a descriptive InternalError when the .pack file cannot be read. Changes
Sequence Diagram(s)(omitted) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip You can get early access to new features in CodeRabbit.Enable the |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@__tests__/test-packfileIntegrity.js`:
- Around line 153-179: Update the assertion to ensure the thrown InternalError
message includes the actual packfile path so regressions that strip the path
fail; after deleting the pack file (variables packDir and packFile) change the
existing expectation on error.data.message (used with readObjectPacked and
Errors.InternalError) to assert that it contains the concrete path (e.g.,
packDir + '/' + packFile or at least packFile) rather than only the generic
"Could not read packfile" prefix.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 569fc30e-f11c-428c-b90b-63023add5053
📒 Files selected for processing (3)
__tests__/test-packfileIntegrity.jssrc/models/GitPackIndex.jssrc/storage/readObjectPacked.js
| // Delete the .pack file but keep the .idx file | ||
| // This causes fs.read() to return null (file not found) | ||
| const packDir = gitdir + '/objects/pack' | ||
| const files = await fs.readdir(packDir) | ||
| const packFile = files.find(f => f.endsWith('.pack')) | ||
| if (!packFile) { | ||
| throw new Error('No packfile found in ' + packDir) | ||
| } | ||
| await fs.rm(packDir + '/' + packFile) | ||
|
|
||
| // Test - should throw InternalError with descriptive message | ||
| let error = null | ||
| try { | ||
| await readObjectPacked({ | ||
| fs, | ||
| cache, | ||
| gitdir, | ||
| oid, | ||
| }) | ||
| } catch (e) { | ||
| error = e | ||
| } | ||
|
|
||
| expect(error).not.toBeNull() | ||
| expect(error instanceof Errors.InternalError).toBe(true) | ||
| expect(error.data.message).toContain('Could not read packfile') | ||
| }) |
There was a problem hiding this comment.
Assert the packfile path too.
Right now this only checks the generic prefix, so a regression that drops the actual path from the message would still pass.
🧪 Suggested test update
- await fs.rm(packDir + '/' + packFile)
+ const packPath = packDir + '/' + packFile
+ await fs.rm(packPath)
...
expect(error.data.message).toContain('Could not read packfile')
+ expect(error.data.message).toContain(packPath)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@__tests__/test-packfileIntegrity.js` around lines 153 - 179, Update the
assertion to ensure the thrown InternalError message includes the actual
packfile path so regressions that strip the path fail; after deleting the pack
file (variables packDir and packFile) change the existing expectation on
error.data.message (used with readObjectPacked and Errors.InternalError) to
assert that it contains the concrete path (e.g., packDir + '/' + packFile or at
least packFile) rather than only the generic "Could not read packfile" prefix.
The CI workflow referenced `test.jest` which does not exist in package-scripts.cjs. The correct script name is `test.node`.
|
🎉 This PR is included in version 1.37.4 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Summary
Fixes #1163 —
GitPackIndexthrows confusingTypeError: Cannot read properties of null (reading 'slice')whenfs.read()returnsnullfor a packfile (e.g.ERR_FS_FILE_TOO_LARGE, missing file, permission error).Root cause:
FileSystem.read()catches all errors and returnsnull. InGitPackIndex.readSlice(), the guardif (!this.pack)checks a Promise object (always truthy), so when the Promise resolves tonull, the code falls through to(await this.pack).slice(start)which throws an unhelpful TypeError.Fix:
readSlice()so the guard actually worksreadObjectPacked.jswith a descriptive error message that includes the packfile pathp.pack = null) so transient errors don't become permanent failuresInternalErroris thrown when a packfile cannot be readTest plan
should throw descriptive error when packfile cannot be read— deletes.packfile, verifiesInternalErrorwith message containing packfile pathtest-readObject(17/17) andtest-readBlob(10/10) unaffectedSummary by CodeRabbit
Bug Fixes
Tests