isar / hive

Lightweight and blazing fast key-value database written in pure Dart.
Apache License 2.0
4.11k stars 410 forks source link

Unhandled Exception: FileSystemException: Cannot create file, path #153

Open mdrideout opened 4 years ago

mdrideout commented 4 years ago

Steps to Reproduce Upgraded previously working app using HiveDB to Hive 1.2.0

Error

Syncing files to device iPhone 11 Pro Max...
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: FileSystemException: Cannot create file, path = '/Users/matt/Library/Developer/CoreSimulator/Devices/03D89D69-AF9B-4C27-B92E-52324FE97F34/data/Containers/Data/Application/D0964550-86ED-43BE-A833-41BE76271E58/Documents/contactsbox.hive' (OS Error: No such file or directory, errno = 2)
#0      _File.create.<anonymous closure> (dart:io/file_impl.dart:265:9)
#1      _rootRunUnary (dart:async/zone.dart:1134:38)
#2      _CustomZone.runUnary (dart:async/zone.dart:1031:19)
#3      _FutureListener.handleValue (dart:async/future_impl.dart:139:18)
#4      Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:680:45)
#5      Future._propagateToListeners (dart:async/future_impl.dart:709:32)
#6      Future._completeWithValue (dart:async/future_impl.dart:524:5)
#7      Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:554:7)
#8      _rootRun (dart:async/zone.dart:1126:13)
#9      _CustomZone.run (dart:async/zone.dart<…>
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: FileSystemException: Cannot create file, path = '/Users/matt/Library/Developer/CoreSimulator/Devices/03D89D69-AF9B-4C27-B92E-52324FE97F34/data/Containers/Data/Application/D0964550-86ED-43BE-A833-41BE76271E58/Documents/contactsbox.hive' (OS Error: No such file or directory, errno = 2)
#0      _File.create.<anonymous closure> (dart:io/file_impl.dart:265:9)
#1      _rootRunUnary (dart:async/zone.dart:1134:38)
#2      _CustomZone.runUnary (dart:async/zone.dart:1031:19)
#3      _FutureListener.handleValue (dart:async/future_impl.dart:139:18)
#4      Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:680:45)
#5      Future._propagateToListeners (dart:async/future_impl.dart:709:32)
#6      Future._completeWithValue (dart:async/future_impl.dart:524:5)
#7      Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:554:7)
#8      _rootRun (dart:async/zone.dart:1126:13)
#9      _CustomZone.run (dart:async/zone.dart<…>

Code sample

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_hive_example/models/contact.dart';
import 'package:flutter_hive_example/screens/add_contact_screen.dart';
import 'package:provider/provider.dart';
import 'package:flutter_hive_example/models/contact_data.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_hive_example/screens/contacts_screen.dart';

void main() {
  Hive.registerAdapter(ContactAdapter(), 0);
  runApp(MyApp());
}

Future _initHive() async {
  var dir = await getApplicationDocumentsDirectory();
  Hive.init(dir.path);
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      builder: (context) => ContactsData(),
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        initialRoute: '/',
        routes: {
          '/': (context) => FutureBuilder(
                future: _initHive(),
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.done) {
                    if (snapshot.error != null) {
                      print(snapshot.error);
                      return Scaffold(
                        body: Center(
                          child: Text('Error initializing hive data store.'),
                        ),
                      );
                    } else {
                      return ContactsScreen();
                    }
                  } else {
                    return Scaffold();
                  }
                },
              ),
          '/AddContactScreen': (context) => AddContactScreen(),
        },
      ),
    );
  }
}

contact.dart

/**
 * Our contact data model
 */

import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';

part 'contact.g.dart';

@HiveType() // use Hive to generate a type adapter
class Contact {
  // Define variables

  @HiveField(0)
  final String name;

  @HiveField(1)
  final String phone;

  @HiveField(2)
  final String email;

  // Constructor
  Contact({@required this.name, this.phone, this.email});
}

contact_data.dart

/**
 * Manages the data for our contacts
 */

import 'package:flutter/foundation.dart';
import 'contact.dart';
import 'package:hive/hive.dart';

class ContactsData extends ChangeNotifier {
  // Name our hive box for this data
  String _boxName = "contactsBox";

  // Initialize our list of contacts
  List<Contact> _contacts = [];

  /// Get Contacts
  /// Gets all contacts from the hive box and loads them into our state List
  void getContacts() async {
    var box = await Hive.openBox<Contact>(_boxName);

    // Update our provider state data with a hive read, and refresh the ui
    _contacts = box.values.toList();
    notifyListeners();
  }

  /// Get Contact
  /// Retrieves a specific contact from our state
  Contact getContact(index) {
    return _contacts[index];
  }

  /// Contact Count
  /// Returns the length of the contact array
  int get contactCount {
    return _contacts.length;
  }

  /// Add Contact
  /// - Saves contact data to Hive box persistent storage
  /// - Updates our List with the hive data by read
  /// - Notifies listeners to update the UI, which will be a consumer of the _contacts List
  void addContact(Contact newContact) async {
    var box = await Hive.openBox<Contact>(_boxName);

    // Add a contact to our box
    await box.add(newContact);

    // Update our provider state data with a hive read, and refresh the ui
    _contacts = box.values.toList();
    notifyListeners();
  }

  /// Delete Contact
  /// - Deletes the contact from Hive
  /// - Updates our List from Hive
  /// - Notifies listeners to update the UI
  void deleteContact(index) async {
    var box = await Hive.openBox<Contact>(_boxName);

    print("Box Keys: " + box.keys.toList().toString());
    print("Deleting Index " +
        index.toString() +
        " which has a box key value of: " +
        box.keys.toList()[index].toString());

    // Get key of box we want to delete
    var boxKey = box.keys.toList()[index];

    // Delete the contact from the box
    await box.delete(boxKey);

    // Update our provider state data with a hive read, and refresh the ui
    _contacts = box.values.toList();
    notifyListeners();
  }
}

Version

simc commented 4 years ago

Thanks, I'm trying to run your code.

Edit: It works fine on Android and I currently don't have an iOS device to test on. Do you see this issue also on Android devices?

mdrideout commented 4 years ago

That error was on the iOS simulator on Mac (iPhone 11 Pro Max, Software Version 13.3)

More Tests (all of these are fresh install, no previous version of app installed)

Deleted App & Tested Again On Simulator iPhone 11 Pro Max I tried uninstalling the app, and then testing again on the iPhone 11 Pro Max simulator and it worked fine!

I am developing 2 apps with very similar hive structure and had the same error message on both of them.

Solution Uninstalling the previously installed version of the app, then doing a fresh "run" from Android Studio fixed the issue.

Potential 1.1.1 -> 1.2.0 Upgrade / Downgrade Issue

iOS Simulator

So this appears to be an upgrade / downgrade issue for this version.

Real iOS device

Android Devices

simc commented 4 years ago

Thank you for your detailed analysis. This is a very weird issue. I'll try to get access to an iOS simulator to reproduce this behavior.

huextrat commented 4 years ago

I had the same error on iOS when I wanted to do the version upgrade. The description made by @mdrideout corresponds perfectly to the problem which is also present when upgrading from 1.1.1 to 1.3.0.

bl0ck3man commented 4 years ago

I've the same issue. @leisim if you have a possibility to fix just do it, please.

bl0ck3man commented 4 years ago

@leisim Is it actual for 1.4.1 ?

ilyasdirin commented 4 years ago

I have the same issue on Android emulator for API 29 for the version ^1.4.1+1.

maxim-saplin commented 4 years ago

Had same exception on Flutter 1.19.0-4.3pre and Hive 1.4.1+1, Android Emulator API level 29 at Hive.openBox

  Dictionary() {
    const file = 'assets/EnRuBig.json';

    Hive.initFlutter().then((value) {
      Hive.openBox<String>(file).then((box) {
        _box = box;

When I changed the box name from the value in "file" (containing slashes, it is also used latter to load data from bundled asset) to simple "EnRuBig" then it worked for me.

cedvdb commented 2 years ago

I had the same issue when the box name contained slash in integration tests, IE:

'tests/test_${testName}_${DateTime.now().microsecond}'.

It might be worth to assert that the name does not contain black listed characters or replace those characters.

Tom3652 commented 1 year ago

Could it be related to the non-relative path on iOS : D0964550-86ED-43BE-A833-41BE76271E58 because the app directory ID is changed by the OS for each app session

creatorpiyush commented 1 year ago

Is there any update regarding this issue?