Skip to content

sqflite_tvos: resolve getDatabasesPath under Library/Caches (Documents isn't writable on device) - #4

Merged
MAUstaoglu merged 2 commits into
fluttertv:mainfrom
SupposedlySam:fix/tvos-writable-databases-path
Jul 20, 2026
Merged

sqflite_tvos: resolve getDatabasesPath under Library/Caches (Documents isn't writable on device)#4
MAUstaoglu merged 2 commits into
fluttertv:mainfrom
SupposedlySam:fix/tvos-writable-databases-path

Conversation

@SupposedlySam

Copy link
Copy Markdown
Contributor

Thanks for the plugin ports — sqflite on tvOS worked well once the database landed in the right place. Sharing a hardware finding in case it's useful, since the simulator hides it.

Why

On a physical Apple TV the tvOS sandbox doesn't allow writing under Documents, but getDatabasesPath() resolves there — so the canonical openDatabase(join(await getDatabasesPath(), 'x.db')) fails at open with SQLITE_CANTOPEN. The simulator sandbox permits the write, so it only shows up on real hardware. Library/Caches is writable, so this points the default there. (README updated to match; the previous note recommended Documents / Application Support.)

Repro

  1. flutter-tvos create demo && cd demo, add sqflite + sqflite_tvos, path, path_provider + path_provider_tvos
  2. at startup: final db = await openDatabase(join(await getDatabasesPath(), 'x.db'));
  3. set DEVELOPMENT_TEAM, flutter-tvos build tvos --profile, install + launch on a physical Apple TV

Before

error opening!: 14
Could not create database queue for path …/Documents/x.db
Could not open db.

After

getDatabasesPath() → …/Library/Caches
openDatabase(...) succeeds

Verified on an Apple TV 4K (tvOS 26.5): the default-path open now succeeds under Library/Caches. One trade-off worth noting in case it matters for the default — Caches is purgeable by the OS, so durable data shouldn't live in a plain sqflite DB on tvOS regardless; the README now says as much.

Documents is not writable in the tvOS sandbox on physical devices, so
the previous default failed every openDatabase with SQLITE_CANTOPEN
(the simulator sandbox permits the write, masking it). Caches is the
tvOS-writable location consistent with the platform's purgeable-storage
model.

@MAUstaogluMAUstaoglu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks — this is a well-evidenced report, and the hardware/simulator split is exactly the kind of thing that's easy to miss. The change itself is right: tvOS only guarantees writable storage under Library/Caches and tmp, so resolving getDatabasesPath() to Documents was never going to work on a real device.

I checked one thing before asking for changes: handleOpenDatabaseCall already creates the parent directory (SqflitePlugin.m:516-526), so returning the Caches path without an explicit createDirectory is fine here — Library/Caches gets created on first open if it's missing. No extra work needed on that front.

Two things before this can merge:

1. Version bump + CHANGELOG.sqflite_tvos is published on pub.dev at 0.0.1, so the fix can't reach users without version: 0.0.2 in pubspec.yaml and a matching ## 0.0.2 entry in CHANGELOG.md.

2. Call out the behaviour change in that entry. Anyone who developed against the simulator has a database sitting under Documents; after this lands getDatabasesPath() points elsewhere and they'll silently get a fresh empty DB rather than an error. Harmless on device (it never worked there), but it should be written down.

Suggested entry:

## 0.0.2***Fix:**`getDatabasesPath()` now resolves under `Library/Caches` instead of
Documents. On a physical Apple TV the tvOS sandbox does not permit writes to
Documents, so the canonical
`openDatabase(join(await getDatabasesPath(), 'x.db'))` failed with
`SQLITE_CANTOPEN`. The simulator sandbox permits the write, which masked this.
***Behaviour change:** apps that created a database against the simulator under
the old Documents path will resolve to a new, empty database. tvOS storage is
purgeable by platform contract — data that must survive belongs on a server or
in iCloud Key-Value Storage.

Separately, and not your problem to fix here: this implies path_provider_tvos has the same issue — it returns .documentDirectory for getApplicationDocumentsDirectory(), and its header comment claims the standard NSSearchPath* lookups "work unchanged" on tvOS. If Documents isn't writable on hardware, that comment is wrong and the directory is unusable. I'll open a separate issue to verify and fix that.

Nice catch — please push the version bump and CHANGELOG and I'll merge.

MAUstaoglu added a commit that referenced this pull request Jul 20, 2026
Adds a PR template covering the two things most easily missed in this
monorepo: per-package version bumps and CHANGELOG entries.
Every package here is published to pub.dev independently, so a
user-visible fix that doesn't bump pubspec.yaml never reaches anyone —
which is exactly what happened in #4. The template also asks whether a
change was verified on real hardware rather than only the simulator,
since the simulator's sandbox is more permissive and masks device-only
failures, and prompts contributors to flag behaviour changes and sibling
packages affected by the same tvOS constraint.
…th fix
Requested in PR review: version bump so the fix can ship to pub.dev, and
a CHANGELOG entry documenting the behaviour change for simulator-created
databases under the old Documents path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@SupposedlySam

Copy link
Copy Markdown
ContributorAuthor

Thank you! Ready for your review.

@MAUstaoglu

Copy link
Copy Markdown
Member

Version bump and CHANGELOG look right — thanks for turning that around.

Worth adding for the record: I verified your premise independently on a physical Apple TV 4K (tvOS 26.5) with a plain dart:io probe, since the simulator can't answer it. Writing a file into each sandbox directory:

directoryresult
tmpwritable
Library/Cacheswritable
DocumentsdeniedOperation not permitted (errno 1); the directory exists, the write is refused
Library/Application Supportdenied — does not exist and cannot be created

So your diagnosis holds exactly, and Library/Caches is the right target.

Two notes that came out of it:

handleOpenDatabaseCall already creates the parent directory (SqflitePlugin.m:516-526), so returning the Caches path without an explicit createDirectory is safe — Library/Caches exists on device anyway, and would be created if it didn't.

More interesting: this isn't limited to sqflite. path_provider_tvos returns Documents for getApplicationDocumentsDirectory() and calls createDirectory on Application Support for getApplicationSupportDirectory() — per the probe, the first hands back a path that can't be written and the second silently swallows a failed creation (try?) and returns a path that doesn't exist. Its header comment claims tvOS has "a normal app sandbox (Documents, Library, Library/Caches, Library/Application Support)" and that the standard lookups "work unchanged", which is wrong for two of the four directories it names. That's a separate fix and I'll handle it.

Merging. Thanks for taking the time to write this up properly — the before/after and the repro made it straightforward to confirm.

Sign up for freeto 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

@SupposedlySam@MAUstaoglu