Skip to content

Treat remote 404 as missing preview in readRemoteFile#197

Merged
khaliqgant merged 1 commit into
mainfrom
fix/remote-file-404-missing-preview
Jun 10, 2026
Merged

Treat remote 404 as missing preview in readRemoteFile#197
khaliqgant merged 1 commit into
mainfrom
fix/remote-file-404-missing-preview

Conversation

@khaliqgant

Copy link
Copy Markdown
Member

Problem

Navigating Pear Issues logged an error in the main process:

Error occurred in handler for 'integrations:read-remote-file': RelayFileApiError: not found
  status: 404, code: 'not_found'

Root cause

The Issues store enriches each Linear issue with its linked GitHub record by reading a synthetic path /github/repos/{owner}/{repo}/issues/{number}.json (issues-store.ts:192), derived from Linear sync metadata. This project's integration setup does not download historical provider records locally, so that file often doesn't exist remotely → the RelayFile API returns 404.

The renderer already recovers — readGithubLink wraps the read in .catch(() => null) and falls back to a basic GitHub link — so the Issues view itself wasn't broken. But readRemoteFile threw on the 404, so Electron logged the rejected IPC handler regardless of the renderer's catch.

Fix

readRemoteFile now catches a 404 and returns a { kind: 'missing' } preview instead of throwing, mirroring how the local filesystem path (readTextPreview in filesystem.ts:60) already reports absent files.

Both callers act only on kind === 'text', so they degrade cleanly:

  • Missing GitHub enrichment falls back to the basic link.
  • A race where an issue file vanishes between directory listing and read skips that issue rather than failing the whole board.

The scope-guard rejections (out-of-scope reads) are unaffected — they throw before the remote call.

Testing

  • Added a regression test asserting an in-scope 404 yields a missing preview rather than rejecting.
  • All 33 tests in integrations.test.ts pass.

Note: main-process change — takes effect after a rebuild + restart of Pear.

🤖 Generated with Claude Code

Navigating Pear Issues logged a RelayFileApiError 404 from the
integrations:read-remote-file IPC handler. The Issues store enriches
each Linear issue with its linked GitHub record by reading a synthetic
path (/github/repos/{owner}/{repo}/issues/{number}.json) derived from
Linear sync metadata. Because historical provider records are not
downloaded locally, that file often does not exist remotely and the
RelayFile API returns 404.

The renderer already recovers (readGithubLink wraps the read in
.catch(() => null) and falls back to a basic link), but readRemoteFile
threw on the 404, so Electron logged the rejected IPC handler regardless.

Make readRemoteFile catch a 404 and return a { kind: 'missing' } preview,
mirroring how the local filesystem path (readTextPreview) already reports
absent files. Both callers act only on kind === 'text', so they degrade
cleanly: missing GitHub enrichment falls back to the basic link, and a
race where an issue file vanishes between listing and read skips that
issue rather than failing the board.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codeant-ai

codeant-ai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Your free trial PR review limit of 300 PRs has been reached. Please upgrade your plan to continue using CodeAnt AI.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

IntegrationsManager.readRemoteFile now catches HTTP 404 errors from remote file reads and returns a missing preview response, while re-throwing all other errors. A new test verifies this 404 handling behavior.

Changes

Remote file 404 error handling

Layer / File(s) Summary
404 error handling in readRemoteFile
src/main/integrations.ts
readRemoteFile wraps the remote read in try/catch; when HTTP 404 is returned, the method resolves to a missing preview object instead of throwing; other errors are re-thrown.
Test coverage for 404 handling
src/main/integrations.test.ts
New test case verifies that readRemoteFile resolves to a missing preview (kind: 'missing', size: 0) when the remote client returns a 404 error, instead of rejecting.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A remote file went missing today,
No error thrown, just kind: 'missing' to say.
Four-oh-four caught with graceful care,
Tests hop along—the logic is fair! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: handling remote 404 errors as missing previews in readRemoteFile, which matches the core purpose of the changeset.
Description check ✅ Passed The description is comprehensively related to the changeset, explaining the problem, root cause, fix, and testing approach in detail.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/remote-file-404-missing-preview

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@agent-relay-code

Copy link
Copy Markdown
Contributor

pr-reviewer could not complete review for #197 in AgentWorkforce/pear.
The review harness exited with code 1.
No review was posted; this needs operator attention.

1 similar comment
@agent-relay-code

Copy link
Copy Markdown
Contributor

pr-reviewer could not complete review for #197 in AgentWorkforce/pear.
The review harness exited with code 1.
No review was posted; this needs operator attention.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/integrations.test.ts`:
- Around line 956-973: Add a test that ensures non-404 errors from the relay are
re-thrown: copy the pattern from the existing 404 test in integrations.test.ts
but have mock.relayClient.readFile.mockImplementationOnce throw an Error/object
with status: 500 (or a network error), then call new
IntegrationsManager().readRemoteFile('project-1', '/slack/...json') and assert
the promise rejects with that same error (use expect(...).rejects.toThrow or
.rejects.toMatchObject to verify the error/status). Reference readRemoteFile,
IntegrationsManager and mock.relayClient.readFile when locating where to insert
the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0701d3e3-ca9e-4720-81e8-6c66499d039e

📥 Commits

Reviewing files that changed from the base of the PR and between 599b033 and c4cbe54.

📒 Files selected for processing (2)
  • src/main/integrations.test.ts
  • src/main/integrations.ts

Comment on lines +956 to +973
it('returns a missing preview when an in-scope remote read 404s instead of rejecting', async () => {
// Historical provider records (e.g. the GitHub issue JSON synthesized from
// Linear sync metadata) are not downloaded locally, so an in-scope read can
// legitimately 404. It must degrade to a missing preview rather than reject
// the IPC handler.
mock.relayClient.readFile.mockImplementationOnce(async (_workspaceId: string, path: string) => {
mock.readFileCalls.push({ workspaceId: _workspaceId, path })
throw Object.assign(new Error('not found'), { status: 404, code: 'not_found' })
})

const manager = new IntegrationsManager()
const preview = await manager.readRemoteFile(
'project-1',
'/slack/channels/C123/messages/1713220123_001100.json'
)

expect(preview).toMatchObject({ kind: 'missing', size: 0 })
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add test coverage for non-404 errors being re-thrown.

The new 404 test correctly verifies graceful degradation, but there's no test ensuring that non-404 errors (e.g., 500, network failures) are still thrown as expected (per line 1082 in integrations.ts). Without this coverage, a bug that swallows all errors could go undetected.

As per coding guidelines, integration notification changes should include regression tests beyond the happy path. Consider adding a test case that mocks relayClient.readFile to throw a non-404 error (e.g., { status: 500 }) and asserts that readRemoteFile rejects with that error.

🧪 Proposed test for non-404 error propagation
  })

+ it('re-throws non-404 remote read errors instead of returning a missing preview', async () => {
+   mock.relayClient.readFile.mockImplementationOnce(async (_workspaceId: string, path: string) => {
+     mock.readFileCalls.push({ workspaceId: _workspaceId, path })
+     throw Object.assign(new Error('internal server error'), { status: 500 })
+   })
+
+   const manager = new IntegrationsManager()
+
+   await expect(
+     manager.readRemoteFile('project-1', '/slack/channels/C123/messages/1713220123_001100.json')
+   ).rejects.toThrow('internal server error')
+ })
+
  it('rejects targeted remote file reads outside the project integration scope', async () => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('returns a missing preview when an in-scope remote read 404s instead of rejecting', async () => {
// Historical provider records (e.g. the GitHub issue JSON synthesized from
// Linear sync metadata) are not downloaded locally, so an in-scope read can
// legitimately 404. It must degrade to a missing preview rather than reject
// the IPC handler.
mock.relayClient.readFile.mockImplementationOnce(async (_workspaceId: string, path: string) => {
mock.readFileCalls.push({ workspaceId: _workspaceId, path })
throw Object.assign(new Error('not found'), { status: 404, code: 'not_found' })
})
const manager = new IntegrationsManager()
const preview = await manager.readRemoteFile(
'project-1',
'/slack/channels/C123/messages/1713220123_001100.json'
)
expect(preview).toMatchObject({ kind: 'missing', size: 0 })
})
it('returns a missing preview when an in-scope remote read 404s instead of rejecting', async () => {
// Historical provider records (e.g. the GitHub issue JSON synthesized from
// Linear sync metadata) are not downloaded locally, so an in-scope read can
// legitimately 404. It must degrade to a missing preview rather than reject
// the IPC handler.
mock.relayClient.readFile.mockImplementationOnce(async (_workspaceId: string, path: string) => {
mock.readFileCalls.push({ workspaceId: _workspaceId, path })
throw Object.assign(new Error('not found'), { status: 404, code: 'not_found' })
})
const manager = new IntegrationsManager()
const preview = await manager.readRemoteFile(
'project-1',
'/slack/channels/C123/messages/1713220123_001100.json'
)
expect(preview).toMatchObject({ kind: 'missing', size: 0 })
})
it('re-throws non-404 remote read errors instead of returning a missing preview', async () => {
mock.relayClient.readFile.mockImplementationOnce(async (_workspaceId: string, path: string) => {
mock.readFileCalls.push({ workspaceId: _workspaceId, path })
throw Object.assign(new Error('internal server error'), { status: 500 })
})
const manager = new IntegrationsManager()
await expect(
manager.readRemoteFile('project-1', '/slack/channels/C123/messages/1713220123_001100.json')
).rejects.toThrow('internal server error')
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/integrations.test.ts` around lines 956 - 973, Add a test that
ensures non-404 errors from the relay are re-thrown: copy the pattern from the
existing 404 test in integrations.test.ts but have
mock.relayClient.readFile.mockImplementationOnce throw an Error/object with
status: 500 (or a network error), then call new
IntegrationsManager().readRemoteFile('project-1', '/slack/...json') and assert
the promise rejects with that same error (use expect(...).rejects.toThrow or
.rejects.toMatchObject to verify the error/status). Reference readRemoteFile,
IntegrationsManager and mock.relayClient.readFile when locating where to insert
the test.

Source: Coding guidelines

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the IntegrationsManager to gracefully handle 404 errors when reading remote files by returning a missing preview object instead of throwing an error, mirroring local filesystem behavior. A corresponding unit test has been added to verify this behavior. There are no review comments, so I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@agent-relay-code

Copy link
Copy Markdown
Contributor

pr-reviewer could not complete review for #197 in AgentWorkforce/pear.
The review harness exited with code 1.
No review was posted; this needs operator attention.

1 similar comment
@agent-relay-code

Copy link
Copy Markdown
Contributor

pr-reviewer could not complete review for #197 in AgentWorkforce/pear.
The review harness exited with code 1.
No review was posted; this needs operator attention.

@khaliqgant khaliqgant merged commit ad9e96e into main Jun 10, 2026
4 checks passed
@khaliqgant khaliqgant deleted the fix/remote-file-404-missing-preview branch June 10, 2026 08:15
@agent-relay-code

Copy link
Copy Markdown
Contributor

pr-reviewer could not complete review for #197 in AgentWorkforce/pear.
The review harness exited with code 1.
No review was posted; this needs operator attention.

1 similar comment
@agent-relay-code

Copy link
Copy Markdown
Contributor

pr-reviewer could not complete review for #197 in AgentWorkforce/pear.
The review harness exited with code 1.
No review was posted; this needs operator attention.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant