firebase/firebase-cpp-sdk

[Bug] [iOS][Storage] Download fails with NSCocoaErrorDomain Code=262 in GetFile() (C++ SDK 12.7.0–12.8.0, 13.0.0)

Closed this issue · 6 comments

[REQUIRED] Please fill in the following fields:

  • Pre-built SDK from the website or open-source from this repo: Pre-built SDK from website
  • Firebase C++ SDK version: 12.7.0 / 12.8.0 / 13.0.0
  • Problematic Firebase Component: Storage
  • Other Firebase Components in use: Auth, Firestore, Functions, Analytics, Messaging, Remote Config
  • Platform you are using the C++ SDK on: macOS
  • Platform you are targeting: iOS

❗️[iOS][Storage] GetFile() download fails with NSCocoaErrorDomain Code=262 on valid file path

Calling StorageReference::GetFile() on iOS fails consistently when attempting to download to a valid sandboxed absolute path. This does not happen on Android or Windows using the same C++ code and Firebase bucket, suggesting the problem lies in the iOS native layer of the C++ SDK.


📄 Error Log Example

Could not remove previous file at /private/var/mobile/Containers/Data/Application/1AADB80E-8E59-4531-83DF-FD292F7BD24C/tmp/CFNetworkDownload_6CZmV6.tmp due to Error Domain=NSCocoaErrorDomain Code=262 "The specified URL type isn’t supported for opening the file." UserInfo={NSFilePath=/var/mobile/Containers/Data/Application/1AADB80E-8E59-4531-83DF-FD292F7BD24C/Documents/patch/asset/100000_100001.zip, NSURL=/var/mobile/Containers/Data/Application/1AADB80E-8E59-4531-83DF-FD292F7BD24C/Documents/patch/asset/100000_100001.zip}

🔍 Relevant Code Snippet (C++ - Firebase Storage Download)

auto app = firebase::App::GetInstance();
if (app == nullptr) return false;
auto storage = firebase::storage::Storage::GetInstance(app);
if (storage == nullptr) return false;
auto storage_ref = storage->GetReference(file_path);
firebase::storage::Controller controller;

auto download_task = storage_ref.GetFile(local_path.c_str(), g_storageListener, &controller);
download_task.OnCompletion([local_path, outputPath](const firebase::Future<size_t>& result) {
    Director::getInstance()->getScheduler()->performFunctionInCocosThread([local_path, outputPath, result]() {
        if (result.status() == firebase::kFutureStatusComplete) {
            if (result.error() == firebase::storage::kErrorNone) {
                auto strExt = cocos2d::FileUtils::getInstance()->getFileExtension(local_path);
                bool bIsZip = strExt == ".zip" || strExt == "zip";
                if (g_storageListener) g_storageListener->onSuccessDownload(bIsZip);
                if (bIsZip) unzipAsync(local_path, outputPath);
            } else {
                if (g_storageListener) g_storageListener->onFailed(result.error(), result.error_message());
            }
        } else {
            if (g_storageListener) g_storageListener->onFailed(result.error(), result.error_message());
        }
    });
});

💡 Root Cause Hypothesis (Confirmed)

In the iOS bridge layer (storage_reference_ios.mm), the SDK currently uses:

NSURL* local_file_url = [NSURL URLWithString:@(path)];  // ❌ This fails for file paths

This should instead be:

NSURL* local_file_url = [NSURL fileURLWithPath:@(path)];  // ✅ Correct for local file access

Using NSURL(string:) for a file path like /var/mobile/... returns nil or misinterprets the path, causing the system to reject the URL and fail with NSCocoaErrorDomain Code=262.

Confirmed at:

NSURL* local_file_url = [NSURL URLWithString:@(path)];


✅ Expected Behavior

  • GetFile() should succeed if destination path is a valid, sandboxed iOS file path
  • SDK should never use NSURL(string:) for absolute file paths

🔧 Suggested Fix

Update line 145 of storage_reference_ios.mm to:

NSURL* local_file_url = [NSURL fileURLWithPath:@(path)];

🧪 Reproduction Steps

  1. On iOS, download a file using StorageReference::GetFile() with an absolute path
  2. Ensure the destination directory exists and the file doesn't
  3. Observe that the download fails and logs NSCocoaErrorDomain 262

💬 Workaround

Delete the file manually before calling GetFile() to avoid the SDK’s internal deletion logic, which fails due to incorrect NSURL handling.


📦 Dependency Versions

  • Firebase C++ SDK: 12.7.0 / 12.8.0 / 13.0.0
  • Firebase iOS SDK: 11.14.0
  • Platform: iOS 16 / 17 tested

From SwiftPM:

Firebase              11.14.0
FirebaseStorage       11.14.0
AppCheck              11.2.0
GoogleAppMeasurement  11.14.0
GoogleUtilities       8.1.0
GoogleDataTransport   10.1.0
GoogleSignIn          8.0.0
GTMAppAuth            4.1.1
GTMSessionFetcher     3.5.0
nanopb                2.30910.0
gRPC                  1.69.0
abseil                1.2024072200.0
Promises              2.4.0
SwiftProtobuf         1.28.2

Thank you for reviewing this issue!

Hi @dconeybe,

Thanks for your work on the Firebase C++ SDK.
This iOS issue related to StorageReference::GetFile() and NSURL handling seems still present in 13.0.0.

Would appreciate it if you could take a look.
The relevant code is here:

NSURL* local_file_url = [NSURL URLWithString:@(path)];

Thanks again!

@pbs0512, Thanks for flagging this and providing such detailed info, I will check it out.

As a quick update, the problem seems to mostly be around the expectations of the path string. It is expecting the path string to be formatted like file://path_to_file, instead of just path_to_file. I'll see about making this a bit less restrictive, especially since you are saying it works without that extra step on Android and Windows.

Thank you for the fix! Do you know when it will be applied?

It should be out in the next release, which will hopefully be next week (assuming no delays come up)