Skip to content

Handle import errors in popup data restore#956

Open
PeterDaveHello wants to merge 1 commit intoChatGPTBox-dev:masterfrom
PeterDaveHello:handle-import-errors
Open

Handle import errors in popup data restore#956
PeterDaveHello wants to merge 1 commit intoChatGPTBox-dev:masterfrom
PeterDaveHello:handle-import-errors

Conversation

@PeterDaveHello
Copy link
Member

@PeterDaveHello PeterDaveHello commented Mar 15, 2026

Wrap the popup import flow in a try/catch so file read, JSON parse, and storage errors no longer surface as unhandled promise rejections.

Keep the successful import path unchanged and show a simple user-facing error when restoring data fails.


Open with Devin

Summary by CodeRabbit

  • Bug Fixes
    • Improved import flow: malformed or unreadable files are now rejected and not applied.
    • Failures during import now produce clear console messages and user-facing alerts with error details.
    • Enhanced validation prevents invalid data from being imported and preserves the existing successful import behavior (followed by a page refresh).

@PeterDaveHello PeterDaveHello requested a review from Copilot March 15, 2026 16:25
@qodo-code-review
Copy link
Contributor

Review Summary by Qodo

Handle import errors in popup data restore

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Wrap popup import flow in try/catch to handle errors gracefully
• Add error handling for file read, JSON parse failures
• Show user-facing error alert instead of unhandled rejections
• Add FileReader error handler for file read failures
Diagram
flowchart LR
  A["File Selection"] --> B["Read File"]
  B --> C{"Parse JSON"}
  C -->|Success| D["Import to Storage"]
  D --> E["Reload Window"]
  C -->|Error| F["Show Error Alert"]
  B -->|Error| F
  D -->|Error| F
Loading

Grey Divider

File Changes

1. src/popup/sections/GeneralPart.jsx 🐞 Bug fix +21/-7

Add comprehensive error handling to data import flow

• Wrapped file import logic in try/catch block for error handling
• Added reject callback to FileReader Promise for JSON parse errors
• Added FileReader.onerror handler to catch file read failures
• Display user-facing error alert with error message on import failure
• Log import errors to console for debugging

src/popup/sections/GeneralPart.jsx


Grey Divider

Qodo Logo

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the stability and user experience of the data import feature within the popup. By wrapping the entire import flow in robust error handling, it ensures that issues arising from file reading, JSON parsing, or storage operations are gracefully caught and communicated to the user, preventing unexpected application crashes and improving overall reliability.

Highlights

  • Robust Data Import: Implemented comprehensive error handling for the popup's data import functionality, covering file reading, JSON parsing, and storage operations.
  • User Feedback: Introduced user-facing alerts to clearly communicate import failures, enhancing the user experience.
  • Error Prevention: Prevented unhandled promise rejections by gracefully catching errors throughout the data import process.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/popup/sections/GeneralPart.jsx
    • Wrapped the data import logic in a try...catch block to handle potential errors.
    • Added specific error handling for JSON parsing within the file reader's onload event.
    • Implemented an onerror handler for the FileReader to catch file reading issues.
    • Displayed user-friendly alert messages when data import fails.
Activity
  • No specific activity (comments, reviews, progress) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Mar 15, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Remediation recommended

1. Unlocalized import error 🐞 Bug ✓ Correctness
Description
When FileReader fails, the code creates a hard-coded English Error('Failed to read import file') and
then displays error.message in a popup alert, bypassing the translation system used throughout the
popup. Non-English users will see mixed-language UI (localized "Error" prefix but English/technical
message body).
Code

src/popup/sections/GeneralPart.jsx[R581-590]

+                reader.onerror = () => {
+                  reject(reader.error || new Error('Failed to read import file'))
+                }
+                reader.readAsText(file)
+              })
+              await importDataIntoStorage(Browser.storage.local, data)
+              window.location.reload()
+            } catch (error) {
+              console.error('[popup] Failed to import data', error)
+              window.alert(`${t('Error')}: ${error.message || error}`)
Evidence
GeneralPart is an i18n-enabled component (react-i18next) and localizes user-visible strings via
t(...), but the newly added FileReader error message is a raw English string that is shown directly
to users via window.alert using error.message.

src/popup/sections/GeneralPart.jsx[45-47]
src/popup/sections/GeneralPart.jsx[559-595]
src/popup/sections/GeneralPart.jsx[588-591]
src/_locales/en/main.json[34-36]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A user-facing error string is hard-coded in English (`&#x27;Failed to read import file&#x27;`) and is displayed via `window.alert` using `error.message`, resulting in mixed-language UI for non-English locales.

## Issue Context
The popup uses `react-i18next` (`t(...)`) broadly for user-visible strings, and locale files exist for multiple languages.

## Fix Focus Areas
- src/popup/sections/GeneralPart.jsx[581-590]
- src/_locales/en/main.json[34-36]

## Suggested approach
1. Replace `new Error(&#x27;Failed to read import file&#x27;)` with a localized message, e.g.:
  - `new Error(t(&#x27;Failed to read import file&#x27;))` (if using phrase-keys), or
  - `new Error(t(&#x27;Import file read failed&#x27;))` with a new translation key.
2. Add the new key to locale files (at least `en`, ideally all supported locales), matching the project’s existing localization pattern.
3. Optionally avoid showing raw technical error messages to users by mapping known failures to friendly localized strings and using a generic localized fallback (while still logging the raw error to console).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 55463b5c-f457-48f3-9c15-6918065198ea

📥 Commits

Reviewing files that changed from the base of the PR and between 210926b and f766535.

📒 Files selected for processing (1)
  • src/popup/sections/GeneralPart.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/popup/sections/GeneralPart.jsx

📝 Walkthrough

Walkthrough

The import handler in src/popup/sections/GeneralPart.jsx was rewritten to use file.text() with JSON.parse(await ...), added validation to ensure the parsed value is a plain object, and wrapped the flow in try/catch; on success it calls importDataIntoStorage and reloads, on failure it logs and alerts the error.

Changes

Cohort / File(s) Summary
Import flow & validation
src/popup/sections/GeneralPart.jsx
Replaced prior FileReader/read-and-parse flow with file.text() + JSON.parse(await ...); added validation to require a plain object and throw on invalid data; wrapped in outer try/catch; on failure console.error + alert(error.message); on success preserves importDataIntoStorage then window.location.reload().

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I munched the bytes, then read them slow,

Parsed each line where soft breezes blow,
If something broke, I gave a shout—oh dear!
I logged the snag and pinged the user near,
Now imports hop safely, carrot cheer! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Handle import errors in popup data restore' accurately and concisely describes the main change: adding error handling to the popup data import/restore flow.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Copy link

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

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 effectively addresses unhandled promise rejections during the data import process by wrapping the file reading and parsing logic in a try...catch block. This improves error handling and provides user-facing feedback on failure. I have one suggestion to further simplify the code for better readability and maintainability.

Comment on lines +571 to +591
try {
const data = await new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = (e) => {
try {
resolve(JSON.parse(e.target.result))
} catch (error) {
reject(error)
}
}
reader.onerror = () => {
reject(reader.error || new Error('Failed to read import file'))
}
reader.readAsText(file)
})
await importDataIntoStorage(Browser.storage.local, data)
window.location.reload()
} catch (error) {
console.error('[popup] Failed to import data', error)
window.alert(`${t('Error')}: ${error.message || error}`)
}

Choose a reason for hiding this comment

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

medium

While the current implementation correctly handles errors, it can be simplified by using the Blob.text() method, which is available on File objects. This method returns a promise that resolves with the file's content as a string, which simplifies the code by removing the need to manually wrap FileReader in a Promise. This makes the code more concise and easier to read.

            try {
              const fileContent = await file.text()
              const data = JSON.parse(fileContent)
              await importDataIntoStorage(Browser.storage.local, data)
              window.location.reload()
            } catch (error) {
              console.error('[popup] Failed to import data', error)
              window.alert(`${t('Error')}: ${error.message || error}`)
            }

Copy link
Member Author

Choose a reason for hiding this comment

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

@coderabbitai what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ask

@coderabbitai what do you think?

Answer:

The change is a solid improvement: wrapping the entire import flow in a try/catch (plus reader.onerror + JSON parse rejection) closes the unhandled-promise-rejection hole and gives users a clear failure signal while keeping the success path unchanged (importDataIntoStorage + reload).

A few concrete notes/suggestions:

  • Simplify the file read (agree with the bot suggestion): since file is a File, you can use await file.text() and drop the FileReader promise wrapper entirely. That reduces code and removes edge cases around reader.onload/reader.onerror.

    try {
      const text = await file.text()
      const data = JSON.parse(text)
      await importDataIntoStorage(Browser.storage.local, data)
      window.location.reload()
    } catch (error) {
      console.error('[popup] Failed to import data', error)
      const message = error instanceof Error ? error.message : String(error)
      window.alert(`${t('Error')}: ${message}`)
    }
  • Error message robustness: error.message || error can produce [object Object] for non-Error throwables. Converting via error instanceof Error ? error.message : String(error) (as in your full diff) is safer.

  • Optional: validate the imported shape: your full diff adds a “plain object” check (reject arrays/null). That’s a good guardrail to prevent applying malformed backups. Consider keeping that (and possibly checking required keys if you have a known schema).

  • i18n of messages: t('Error') is good, but "Invalid backup file" / "Failed to read import file" should ideally be translatable too, if this UI is localized.

Overall: 👍 good fix, and I’d recommend the file.text() simplification + the more defensive error-string handling (and keeping the plain-object validation).

Copy link
Contributor

Choose a reason for hiding this comment

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

Skipped: comment is from another GitHub bot.

Copy link
Contributor

Choose a reason for hiding this comment

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

@PeterDaveHello, the Blob.text() suggestion from gemini is a good one — I'd support adopting it. Here's my analysis:

Why it's better:

FileReader.readAsText() is the older API, whereas Blob.text() returns a promise directly, eliminating the manual new Promise((resolve, reject) => { ... }) wrapper and the nested reader.onload/reader.onerror handlers. The result is significantly less boilerplate.

Browser compatibility: Blob.text() is well established and works across many devices and browser versions, and has been available across browsers since April 2021. For a browser extension targeting modern Chrome/Firefox/Edge, there are no compatibility concerns.

One encoding note: Blob.text() always uses UTF-8, while FileReader.readAsText() can use a different encoding depending on the blob's type and a specified encoding name. Since JSON files are virtually always UTF-8, this is a non-issue here.

Combined with the isPlainObject validation (already present in the full file), the refactored version would look like:

try {
  const fileContent = await file.text()
  const parsedData = JSON.parse(fileContent)
  if (parsedData === null || typeof parsedData !== 'object' || Array.isArray(parsedData)) {
    throw new Error('Invalid backup file')
  }
  await importDataIntoStorage(Browser.storage.local, data)
  window.location.reload()
} catch (error) {
  console.error('[popup] Failed to import data', error)
  const message = error instanceof Error ? error.message : String(error ?? t('Error'))
  window.alert(`${t('Error')}: ${message}`)
}

This is cleaner and easier to follow than the FileReader-wrapped-in-Promise approach. I'd recommend adopting it.

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@PeterDaveHello
Copy link
Member Author

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. What shall we delve into next?

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the popup “Import All Data” flow by catching failures during file read, JSON parsing, and storage writes so they don’t become unhandled promise rejections, and surfaces a user-facing error instead.

Changes:

  • Wrapes the import flow in try/catch to handle failures gracefully.
  • Adds FileReader error handling and propagates JSON parse failures.
  • Logs import failures and shows an alert to the user.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +590 to +591
const message = error instanceof Error ? error.message : String(error ?? t('Error'))
window.alert(`${t('Error')}: ${message}`)
Copy link
Member Author

Choose a reason for hiding this comment

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

@coderabbitai what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

@PeterDaveHello, Copilot's suggestion has partial merit. Here's the breakdown:

Where the current approach works well:

  • The two custom error messages ("Invalid backup file" and "Failed to read import file") are already user-friendly and will display cleanly as-is.

Where Copilot has a point:

  • JSON.parse throws browser-generated errors like "Unexpected token '<', "<!DOCTYPE ..." is not valid JSON" — these are technical and confusing for end users.
  • Errors from importDataIntoStorage are also unpredictable.

Recommended middle-ground — map known error categories to localized messages while keeping the raw detail in console.error (which already happens):

} catch (error) {
  console.error('[popup] Failed to import data', error)
  let message
  if (error instanceof SyntaxError) {
    message = t('Invalid JSON format in backup file')
  } else if (error instanceof Error) {
    message = error.message // already user-friendly for custom errors
  } else {
    message = t('Error')
  }
  window.alert(`${t('Error')}: ${message}`)
}

This way:

  • SyntaxError from JSON.parse → localized, clean message
  • Custom Error objects ("Invalid backup file", "Failed to read import file") → shown as-is (already friendly)
  • Unknown/non-Error throws → generic t('Error') fallback

Copilot's suggestion to fully replace everything with a single opaque message would be too aggressive and lose useful context. The middle-ground above addresses the legitimate UX concern without over-engineering it.

@PeterDaveHello
Copy link
Member Author

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Improves the extension popup’s “Import All Data” restore flow by preventing unhandled promise rejections and surfacing failures to users.

Changes:

  • Wraps file read → JSON parse → storage import in a try/catch.
  • Adds basic validation that imported JSON is a plain object before writing to storage.
  • Logs failures to the console and displays a user-facing error alert on import failure.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

window.location.reload()
} catch (error) {
console.error('[popup] Failed to import data', error)
const message = error instanceof Error ? error.message : String(error ?? t('Error'))
Copy link
Member Author

Choose a reason for hiding this comment

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

@coderabbitai what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

@PeterDaveHello, Copilot's observation is valid. new Error() and new Error('') both produce error.message === '', so the current code can produce an alert that just says "Error: " — not useful for the user. The fallback t('Error') in the ternary's false branch never fires when a bare Error object with no message is thrown.

A minimal, clean fix:

const rawMessage = error instanceof Error ? error.message : String(error ?? '')
const message = rawMessage || t('Error')

Or, if you prefer it as a one-liner using Error.prototype.toString() (which gives at least "Error" instead of "" for a no-message Error):

const message =
  (error instanceof Error ? error.message || error.toString() : String(error ?? '')) || t('Error')

Either approach guarantees the alert always shows a non-empty, localized fallback when no descriptive message is available, while still preferring the actual message when it exists.

Comment on lines 568 to 569
input.click()
})

Choose a reason for hiding this comment

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

(Refers to lines 563-569)

📝 Info: Pre-existing: file picker cancel leaves a hanging promise

The file selection on lines 563-569 creates a Promise that only resolves via input.onchange. In some browsers, if the user cancels the file dialog, onchange never fires, leaving the Promise permanently pending. This is a pre-existing issue not introduced by this PR, and the if (!file) return guard on line 570 only helps if onchange fires with an empty file list. A common fix is to listen for a focus or change event on the window/document after input.click() to detect cancellation, or to use input.addEventListener('cancel', ...).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Importing data in the popup assumed file reads, JSON parsing, and
storage writes would always succeed, leaving failures unhandled and
giving users no feedback.

Catch errors across the import flow and validate that parsed backup data
is a plain object before writing it to storage, so invalid files fail
clearly without changing the successful restore path.
@PeterDaveHello
Copy link
Member Author

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. 🎉

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the popup “Import All Data” restore flow so failures during file reading, JSON parsing, or storage writes are handled gracefully instead of producing unhandled promise rejections.

Changes:

  • Wrap the import/restore flow in a try/catch to prevent unhandled promise rejections.
  • Switch from FileReader to await file.text() for reading the selected JSON file.
  • Add basic validation to ensure the parsed JSON is a plain object before importing, and display a user-facing error on failure.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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.

2 participants