Skip to content

fix: fall back to internal storage when external storage is unavailable - #2781

Open
ulite-Amr wants to merge 1 commit into
Acode-Foundation:mainfrom
ulite-Amr:fix/startup-storage-fallback
Open

fix: fall back to internal storage when external storage is unavailable#2781
ulite-Amr wants to merge 1 commit into
Acode-Foundation:mainfrom
ulite-Amr:fix/startup-storage-fallback

Conversation

@ulite-Amr

@ulite-Amr ulite-Amr commented Aug 20, 2026

Copy link
Copy Markdown

What

Fixes the app failing to start on devices where the external storage directory cannot be created. On such devices users were stuck on the splash screen with a misleading "Acode failed to start. Update Android System WebView or Chrome." message — the WebView was fine, the problem was storage.

Reported by

Root cause

  1. src/main.js unconditionally picked the external data directory:
    window.DATA_STORAGE = externalDataDirectory || dataDirectory;
  2. The Cordova file plugin only registers files-external if the external root directory can be created (newRoot.mkdirs() fails on affected devices), so the chosen URL points at a non-existent filesystem.
  3. The subsequent plugins-directory creation was not wrapped in try/catch:
    if (!(await fsOperation(PLUGIN_DIR).exists())) await fsOperation(DATA_STORAGE).createDirectory("plugins");
  4. Its unhandled rejection aborted onDeviceReady() before loadApp(), leaving editorManager null and the splash screen forever — with the error handler blaming WebView/Chrome.

Logcat evidence on an affected device:

FileUtils: Unable to create root dir for filesystem "files-external", skipping
FileUtils: Unable to create root dir for filesystem "cache-external", skipping
Uncaught (in promise) #<FileError> at build/main.js (63221)
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'hasUnsavedFiles')

Changes

  • src/main.js
    • Added resolveStorageDir() — probes the preferred directory with fs.stat() and falls back to internal storage when unavailable
    • Wrapped plugins-directory creation in try/catch; on failure it reassigns DATA_STORAGE/CACHE_STORAGE/PLUGIN_DIR/KEYBINDING_FILE to internal storage and retries
    • Storage permission requests are now guarded: only requested on SDK < 33, and only when hasPermission returns false (ensurePermission() helper), preventing background-activity-launch blocks
  • src/lib/acode.jseditorManager?.hasUnsavedFiles?.() ?? 0 in exitAppMessage (the error above was a downstream symptom of the aborted startup)
  • www/index.html — startup error/rejection handlers now detect storage errors (FileError/NotFoundError/SecurityError/DOMException codes 1-12) and show an honest "Acode failed to start: storage is unavailable" message instead of blaming WebView/Chrome

Tested

The same patch was verified on an affected device: app now falls back to internal storage and starts normally, and storage errors produce an accurate message. CI (biome, typos, vitest) runs on this PR.

Fixes the class of startup failures reported as "Update Android System WebView or Chrome" that actually originate from unavailable external storage.

@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR preserves the application entry points and adds resilient startup behavior when external storage is unavailable.

  • Probes external data and cache directories before selecting them.
  • Falls back to internal storage if plugin-directory creation fails.
  • Avoids unnecessary permission requests and improves startup storage-error messaging.
  • Safely handles exit-message evaluation before the editor manager initializes.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previously reported deletion issue is invalid at the current head because all three application entry-point files remain present and contain targeted modifications.

Important Files Changed

Filename Overview
src/main.js Adds storage probing and internal fallback during bootstrap while conditionally requesting Android permissions.
src/lib/acode.js Makes the exit message safe before editorManager has initialized.
www/index.html Distinguishes storage-related startup failures from WebView compatibility failures.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Device ready] --> B[Probe external storage]
    B -->|Available| C[Use external data and cache]
    B -->|Unavailable| D[Use internal data and cache]
    C --> E[Ensure plugins directory]
    E -->|Creation succeeds| F[Continue application bootstrap]
    E -->|Creation fails| D
    D --> G[Ensure internal plugins directory]
    G --> F
Loading

Reviews (2): Last reviewed commit: "fix: fall back to internal storage when ..." | Re-trigger Greptile

@ulite-Amr
ulite-Amr marked this pull request as draft August 20, 2026 22:08
@ulite-Amr
ulite-Amr force-pushed the fix/startup-storage-fallback branch from 313fcca to e6fd161 Compare August 20, 2026 22:09
@ulite-Amr
ulite-Amr marked this pull request as ready for review August 20, 2026 22:10
The app used to pick the external data directory unconditionally and then
create the plugins directory without guarding against failures. On devices
where the external filesystem cannot be created (e.g. Android/data dir is
not creatable), the unhandled rejection aborted startup, leaving users stuck
on the splash screen with a misleading "Update Android System WebView or
Chrome" message.

- Probe external storage with fs.stat() and fall back to internal storage
- Wrap plugins directory creation in try/catch and fall back to internal
- Request storage permissions only on SDK < 33, guarded by hasPermission
- Guard editorManager.hasUnsavedFiles() access in exitAppMessage
- Show an honest "storage is unavailable" startup message for storage errors
@ulite-Amr
ulite-Amr force-pushed the fix/startup-storage-fallback branch from e6fd161 to 43f8595 Compare August 21, 2026 00:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants