Skip to content

Handle import errors in popup data restore#956

Merged
PeterDaveHello merged 1 commit intoChatGPTBox-dev:masterfrom
PeterDaveHello:handle-import-errors
Mar 16, 2026
Merged

Handle import errors in popup data restore#956
PeterDaveHello merged 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
    • Import now rejects malformed or non-object files to prevent invalid data from being applied.
    • Improved import resilience with broader file-reading support and stricter validation.
    • Failures log clearer messages and display an internationalized alert with the error details.
    • Successful imports retain previous behavior and continue to trigger a full 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: 3e07f06b-2bf6-4312-9efb-1f52b09f635c

📥 Commits

Reviewing files that changed from the base of the PR and between 70002fa and ed5c39d.

📒 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

Rewrote import handler in src/popup/sections/GeneralPart.jsx to parse file text via await file.text() (with FileReader fallback), validate parsed JSON is a plain non-null object (not an array), wrap in try/catch, call importDataIntoStorage and window.location.reload() on success, and console.error + alert(i18n("Error") + ": " + error.message) on failure.

Changes

Cohort / File(s) Summary
Import flow & validation
src/popup/sections/GeneralPart.jsx
Replaced FileReader/onload parsing with await file.text() + JSON.parse and a FileReader fallback; added plain-object validation (non-null, not an array) with explicit throws; wrapped flow in try/catch; on success calls importDataIntoStorage then window.location.reload(); on error logs and alerts using i18n("Error") with the message.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I nibbled bytes and parsed them right,

I checked each shape beneath the light,
If errors sprung, I called them out,
I logged the tumble, quelled the doubt,
Now imports hop along tonight 🥕✨

🚥 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' directly and clearly summarizes 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".

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. 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".

This comment was marked as resolved.

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.

@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.

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

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 to prevent unhandled promise rejections and provide user feedback when a restore fails.

Changes:

  • Wrap the import/restore path in a try/catch to handle file read, JSON parse, and storage errors.
  • Switch to File.text() + JSON.parse and validate the backup is a plain object before importing.
  • On success, keep existing behavior by importing into Browser.storage.local and reloading the page; on failure, log and alert.

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

Comment on lines +582 to +585
} catch (error) {
console.error('[popup] Failed to import data', error)
const rawMessage = error instanceof Error ? error.message : String(error ?? '')
window.alert(rawMessage ? `${t('Error')}: ${rawMessage}` : 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 concern is valid and worth addressing. The PR description says "Shows a simple user-facing error," but a raw SyntaxError from JSON.parse (e.g., "Unexpected token < in JSON at position 0") is quite technical and can confuse non-developer users.

Since the full technical detail is already preserved in console.error, I'd recommend mapping SyntaxError to the same friendly "Invalid backup file" string you already use elsewhere in the try block:

} catch (error) {
  console.error('[popup] Failed to import data', error)
  const displayMessage =
    error instanceof SyntaxError
      ? t('Invalid backup file')
      : error instanceof Error
        ? error.message
        : String(error ?? '')
  window.alert(displayMessage ? `${t('Error')}: ${displayMessage}` : t('Error'))
}

This keeps the UX clean for parse failures while still surfacing meaningful messages for other error types (e.g., storage quota errors from importDataIntoStorage). If 'Invalid backup file' isn't already an i18n key, this would also be a good time to add it.

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 improves the popup “Import All Data” restore flow by preventing unhandled promise rejections and providing a user-visible failure path when file reading/parsing/storage import fails.

Changes:

  • Wraps the import flow in try/catch to prevent unhandled promise rejections during restore.
  • Uses File.text() when available, with a FileReader fallback for compatibility.
  • Validates that parsed JSON is a plain object before importing to extension storage.

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
src/popup/sections/GeneralPart.jsx (1)

585-587: ⚠️ Potential issue | 🟡 Minor

Localize the invalid-backup error text.

Line 586 still throws a hardcoded English message ('Invalid backup file'), which bypasses i18n in user alerts.

💡 Proposed fix
-                throw new Error('Invalid backup file')
+                throw new Error(t('Invalid backup file'))
Based on learnings: new strings must first be added to `src/_locales/en/main.json` before propagating to other locales, and existing keys should not be changed.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/popup/sections/GeneralPart.jsx` around lines 585 - 587, Replace the
hardcoded error string thrown in GeneralPart.jsx (new Error('Invalid backup
file')) with a localized message: first add a new key (e.g.,
"invalid_backup_file") and English text to src/_locales/en/main.json, then
update the throw to use the project's i18n lookup (chrome.i18n.getMessage(...)
or the project's getMessage/t helper) to fetch that key; do not rename existing
locale keys—only add the new key and use it in the throw.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/popup/sections/GeneralPart.jsx`:
- Around line 585-587: Replace the hardcoded error string thrown in
GeneralPart.jsx (new Error('Invalid backup file')) with a localized message:
first add a new key (e.g., "invalid_backup_file") and English text to
src/_locales/en/main.json, then update the throw to use the project's i18n
lookup (chrome.i18n.getMessage(...) or the project's getMessage/t helper) to
fetch that key; do not rename existing locale keys—only add the new key and use
it in the throw.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 121fa3e9-e43a-4539-b3ba-e941679d5602

📥 Commits

Reviewing files that changed from the base of the PR and between f766535 and 70002fa.

📒 Files selected for processing (1)
  • src/popup/sections/GeneralPart.jsx

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.

This comment was marked as resolved.

@PeterDaveHello PeterDaveHello merged commit c4dbc52 into ChatGPTBox-dev:master Mar 16, 2026
8 checks passed
@PeterDaveHello PeterDaveHello deleted the handle-import-errors branch March 16, 2026 19:17
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