isar / hive

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

Unhandled Exception: RangeError: Not enough bytes available. #424

Open anandsubbu007 opened 4 years ago

anandsubbu007 commented 4 years ago
Restarted application in 6,661ms.
W/DynamiteModule(20626): Local module descriptor class for providerinstaller not found.
I/DynamiteModule(20626): Considering local module providerinstaller:0 and remote module providerinstaller:0
W/ProviderInstaller(20626): Failed to load providerinstaller module: No acceptable module found. Local version is 0 and remote version is 0.
W/ConnectivityManager.CallbackHandler(20626): callback not found for CALLBACK_AVAILABLE message
E/flutter (20626): [ERROR:flutter/lib/ui/ui_dart_state.cc(171)] Unhandled Exception: RangeError: Not enough bytes available.
E/flutter (20626): #0      BinaryReaderImpl._requireBytes
E/flutter (20626): #1      BinaryReaderImpl.readByte
E/flutter (20626): #2      StaticModelAdapter.read
E/flutter (20626): #3      BinaryReaderImpl.read
E/flutter (20626): #4      BinaryReaderImpl.readFrame
E/flutter (20626): #5      FrameHelper.framesFromBytes
E/flutter (20626): #6      FrameIoHelper.framesFromFile
E/flutter (20626): <asynchronous suspension>
E/flutter (20626): #7      StorageBackendVm.initialize
E/flutter (20626): <asynchronous suspension>
E/flutter (20626): #8      BoxBaseImpl.initialize
E/flutter (20626): #9      HiveImpl._openBox
E/flutter (20626): <asynchronous suspension>
E/flutter (20626): #10     HiveImpl.openBox
E/flutter (20626): #11     main
E/flutter (20626): <asynchronous suspension>
E/flutter (20626): #12     _runMainZoned.<anonymous closure>.<anonymous closure>  (dart:ui/hooks.dart:231:25)
E/flutter (20626): #13     _rootRun  (dart:async/zone.dart:1190:13)
E/flutter (20626): #14     _CustomZone.run  (dart:async/zone.dart:1093:19)
E/flutter (20626): #15     _runZoned  (dart:async/zone.dart:1630:10)
E/flutter (20626): #16     runZonedGuarded  (dart:async/zone.dart:1618:12)
E/flutter (20626): #17     _runMainZoned.<anonymous closure>  (dart:ui/hooks.dart:223:5)
E/flutter (20626): #18     _startIsolate.<anonymous closure>  (dart:isolate-patch/isolate_patch.dart:301:19)
E/flutter (20626): #19     _RawReceivePortImpl._handleMessage  (dart:isolate-patch/isolate_patch.dart:168:12)
E/flutter (20626):
E/flutter (20626): [ERROR:flutter/lib/ui/ui_dart_state.cc(171)] Unhandled Exception: RangeError: Not enough bytes available.
E/flutter (20626): #0      BinaryReaderImpl._requireBytes
E/flutter (20626): #1      BinaryReaderImpl.readByte
E/flutter (20626): #2      StaticModelAdapter.read
E/flutter (20626): #3      BinaryReaderImpl.read
E/flutter (20626): #4      BinaryReaderImpl.readFrame
E/flutter (20626): #5      FrameHelper.framesFromBytes
E/flutter (20626): #6      FrameIoHelper.framesFromFile
E/flutter (20626): <asynchronous suspension>
E/flutter (20626): #7      StorageBackendVm.initialize
E/flutter (20626): <asynchronous suspension>
E/flutter (20626): #8      BoxBaseImpl.initialize
E/flutter (20626): #9      HiveImpl._openBox
E/flutter (20626): <asynchronous suspension>
E/flutter (20626): #10     HiveImpl.openBox
E/flutter (20626): #11     main
E/flutter (20626): <asynchronous suspension>
E/flutter (20626): #12     _runMainZoned.<anonymous closure>.<anonymous closure>  (dart:ui/hooks.dart:231:25)
E/flutter (20626): #13     _rootRun  (dart:async/zone.dart:1190:13)
E/flutter (20626): #14     _CustomZone.run  (dart:async/zone.dart:1093:19)
E/flutter (20626): #15     _runZoned  (dart:async/zone.dart:1630:10)
E/flutter (20626): #16     runZonedGuarded  (dart:async/zone.dart:1618:12)
E/flutter (20626): #17     _runMainZoned.<anonymous closure>  (dart:ui/hooks.dart:223:5)
E/flutter (20626): #18     _startIsolate.<anonymous closure>  (dart:isolate-patch/isolate_patch.dart:301:19)
E/flutter (20626): #19     _RawReceivePortImpl._handleMessage  (dart:isolate-patch/isolate_patch.dart:168:12)
E/flutter (20626):
themisir commented 4 years ago

Could you reproduce the issue?

anandsubbu007 commented 4 years ago

this issue is solved when i delete local data.

anandsubbu007 commented 4 years ago

Again Facing this issue in flutter web. Can't able to resolve it.

Restarted application in 648ms.
Prest :::::: 123871653
Error: RangeError: Not enough bytes available.
    at Object.throw_ [as throw] (http://localhost:64762/dart_sdk.js:4332:11)
    at binary_reader_impl.BinaryReaderImpl.new.[_requireBytes] (http://localhost:64762/packages/hive/src/box/lazy_box_impl.dart.lib.js:1243:19)
    at binary_reader_impl.BinaryReaderImpl.new.readByte (http://localhost:64762/packages/hive/src/box/lazy_box_impl.dart.lib.js:1252:26)
    at http://localhost:64762/packages/website/Models/User_model.dart.lib.js:437:28
    at User_model.UserDataAdapter.new.read (http://localhost:64762/packages/website/Models/User_model.dart.lib.js:439:9)
    at binary_reader_impl.BinaryReaderImpl.new.read (http://localhost:64762/packages/hive/src/box/lazy_box_impl.dart.lib.js:1501:35)
    at storage_backend_js.StorageBackendJs.new.decodeValue (http://localhost:64762/packages/hive/src/box/lazy_box_impl.dart.lib.js:1628:27)
    at MappedListIterable.new.elementAt (http://localhost:64762/dart_sdk.js:21547:25)
    at ListIterator.new.moveNext (http://localhost:64762/dart_sdk.js:21341:55)
    at JsIterator.next (http://localhost:64762/dart_sdk.js:5999:21)
    at storage_backend_js.StorageBackendJs.new.initialize (http://localhost:64762/packages/hive/src/box/lazy_box_impl.dart.lib.js:1685:20)
    at initialize.next (<anonymous>)
    at http://localhost:64762/dart_sdk.js:37592:33
    at _RootZone.runUnary (http://localhost:64762/dart_sdk.js:37446:58)
    at _FutureListener.thenAwait.handleValue (http://localhost:64762/dart_sdk.js:32430:29)
    at handleValueCallback (http://localhost:64762/dart_sdk.js:32977:49)
    at Function._propagateToListeners (http://localhost:64762/dart_sdk.js:33015:17)
    at _Future.new.[_completeWithValue] (http://localhost:64762/dart_sdk.js:32858:23)
    at async._AsyncCallbackEntry.new.callback (http://localhost:64762/dart_sdk.js:32880:35)
    at Object._microtaskLoop (http://localhost:64762/dart_sdk.js:37707:13)
    at _startMicrotaskLoop (http://localhost:64762/dart_sdk.js:37713:13)
    at http://localhost:64762/dart_sdk.js:33232:9
Error: RangeError: Not enough bytes available.
    at Object.throw_ [as throw] (http://localhost:64762/dart_sdk.js:4332:11)
    at binary_reader_impl.BinaryReaderImpl.new.[_requireBytes] (http://localhost:64762/packages/hive/src/box/lazy_box_impl.dart.lib.js:1243:19)
    at binary_reader_impl.BinaryReaderImpl.new.readByte (http://localhost:64762/packages/hive/src/box/lazy_box_impl.dart.lib.js:1252:26)
    at http://localhost:64762/packages/website/Models/User_model.dart.lib.js:437:28
    at User_model.UserDataAdapter.new.read (http://localhost:64762/packages/website/Models/User_model.dart.lib.js:439:9)
    at binary_reader_impl.BinaryReaderImpl.new.read (http://localhost:64762/packages/hive/src/box/lazy_box_impl.dart.lib.js:1501:35)
    at storage_backend_js.StorageBackendJs.new.decodeValue (http://localhost:64762/packages/hive/src/box/lazy_box_impl.dart.lib.js:1628:27)
    at MappedListIterable.new.elementAt (http://localhost:64762/dart_sdk.js:21547:25)
    at ListIterator.new.moveNext (http://localhost:64762/dart_sdk.js:21341:55)
    at JsIterator.next (http://localhost:64762/dart_sdk.js:5999:21)
    at storage_backend_js.StorageBackendJs.new.initialize (http://localhost:64762/packages/hive/src/box/lazy_box_impl.dart.lib.js:1685:20)
    at initialize.next (<anonymous>)
    at http://localhost:64762/dart_sdk.js:37592:33
    at _RootZone.runUnary (http://localhost:64762/dart_sdk.js:37446:58)
    at _FutureListener.thenAwait.handleValue (http://localhost:64762/dart_sdk.js:32430:29)
    at handleValueCallback (http://localhost:64762/dart_sdk.js:32977:49)
    at Function._propagateToListeners (http://localhost:64762/dart_sdk.js:33015:17)
    at _Future.new.[_completeWithValue] (http://localhost:64762/dart_sdk.js:32858:23)
    at async._AsyncCallbackEntry.new.callback (http://localhost:64762/dart_sdk.js:32880:35)
    at Object._microtaskLoop (http://localhost:64762/dart_sdk.js:37707:13)
    at _startMicrotaskLoop (http://localhost:64762/dart_sdk.js:37713:13)
    at http://localhost:64762/dart_sdk.js:33232:9
themisir commented 4 years ago

Did the issue happened after changing model structure or randomly?

anandsubbu007 commented 4 years ago

nope, it is working fine when i start debugging. after i restart 2-3 time. this error happens

artem-bakuta commented 4 years ago

First application start is ok, but second and all the next causes crash

themisir commented 4 years ago

First application start is ok, but second and all the next causes crash

Could you share code with us to identify cause?

anandsubbu007 commented 4 years ago

when i clear all cache & storage and run builder again this issue is resolved

artem-bakuta commented 4 years ago

I call await StorageHive().init(); before main app class, for the first time is everything ok, but while opening app the second. etc times always error will be. I have to wipe emulator, to reinstall app on real device but problem still exists. Versions of hive and generator are the last from repo's.

Method invokation Place where error occurs Link to Image error

muhammednazil commented 3 years ago

[ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: RangeError: Not enough bytes available.

any find the problem

flutterhive

Dimoshka commented 3 years ago

For several days I suffered with the same problem and could not understand why it appears. Changed package versions and much more.

Everything turned out to be trite. I save the array of enams to the database. I specified the type for enam (@HiveType), but did not specify the indices for the values (@HiveField), and this led to the fact that everything was successfully written to the database, but not read upon restarting!

This fixed my problem.

cosmotek commented 3 years ago

I figured it (atleast in my case).

This was my code:

  SessionTokenInfo read(BinaryReader reader) {
    print("read ${reader.readString()}");
    return SessionTokenInfo.fromJson(jsonDecode(reader.readString()));
  }

I was reading from the same BinaryReader twice. I assume there's a finite buffer that gets cleared as you read. Calling read twice (apparently) was the problem.

I hope this helps someone else.

themisir commented 3 years ago

I figured it (atleast in my case).

This was my code:

  SessionTokenInfo read(BinaryReader reader) {
    print("read ${reader.readString()}");
    return SessionTokenInfo.fromJson(jsonDecode(reader.readString()));
  }

I was reading from the same BinaryReader twice. I assume there's a finite buffer that gets cleared as you read. Calling read twice (apparently) was the problem.

I hope this helps someone else.

reader.readString() moves cursor to end of the read data. So in your case second readString() will throw an error because there might be nothing available to read (Even if there's data, the returned data will not be same as you've printed).

Instead of reading twice you can store value in variable then use it twice.

  SessionTokenInfo read(BinaryReader reader) {
    final str = reader.readString();
    print('read $str');
    return SessionTokenInfo.fromJson(jsonDecode(str));
  }
HumesFork commented 3 years ago

i occur the same problem,i did know what went wrong?

cosmotek commented 3 years ago

@HumesFork please proof-read your comment. The previous comment explain the issue clearly.

@leisim Maybe improve the error message? Seems a decent number of devs all find it unclear.

simc commented 3 years ago

@cosmotek that's not so easy because there are a lot of reasons why this error may happen. Do you have a suggestion?

syedfaisaljaved commented 3 years ago

facing this issue using firestore. when i store firestore data locally and then restart my app. i get the following error -

[ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: RangeError: Not enough bytes available.

0 BinaryReaderImpl._requireBytes (package:hive/src/binary/binary_reader_impl.dart:49:7)

1 BinaryReaderImpl.readByte (package:hive/src/binary/binary_reader_impl.dart:65:5)

2 UserFSDataAdapter.read (package:fluent_life_flutter/db/model/user_model.g.dart:17:52)

3 BinaryReaderImpl.read (package:hive/src/binary/binary_reader_impl.dart:325:33)

4 BinaryReaderImpl.readFrame (package:hive/src/binary/binary_reader_impl.dart:273:26)

5 FrameHelper.framesFromBytes (package:hive/src/binary/frame_helper.dart:17:26)

6 FrameIoHelper.framesFromFile (package:hive/src/io/frame_io_helper.dart:41:12)

#7 StorageBackendVm.initialize (package:hive/src/backend/vm/storage_backend_vm.dart:82:30) #8 BoxBaseImpl.initialize (package:hive/src/box/box_base_impl.dart:90:20) #9 HiveImpl._openBox (package:hive/src/hive_impl.dart:106:22) #10 HiveImpl.openBox (package:hive/src/hive_impl.dart:135:18) #11 HiveProvider.openBox (package:fluent_life_flutter/db/hive_provider.dart:26:16) #12 main (package:fluent_life_flutter/main.dart:15:22) #13 _runMainZoned.. (dart:ui/hooks.dart:231:25) #14 _rootRun (dart:async/zone.dart:1190:13) #15 _CustomZone.run (dart:async/zone.dart:1093:19) #16 _runZoned (dart:async/zone.dart:1630:10) #17 runZonedGuarded (dart:async/zone.dart:1618:12) #18 _runMainZoned. (dart:ui/hooks.dart:223:5) #19 _startIsolate. (dart:isolate-patch/isolate_patch.dart:301:19) #20 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12) [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: RangeError: Not enough bytes available. #0 BinaryReaderImpl._requireBytes (package:hive/src/binary/binary_reader_impl.dart:49:7) #1 BinaryReaderImpl.readByte (package:hive/src/binary/binary_reader_impl.dart:65:5) #2 UserFSDataAdapter.read (package:fluent_life_flutter/db/model/user_model.g.dart:17:52) #3 BinaryReaderImpl.read (package:hive/src/binary/binary_reader_impl.dart:325:33) #4 BinaryReaderImpl.readFrame (package:hive/src/binary/binary_reader_impl.dart:273:26) #5 FrameHelper.framesFromBytes (package:hive/src/binary/frame_helper.dart:17:26) #6 FrameIoHelper.framesFromFile (package:hive/src/io/frame_io_helper.dart:41:12) #7 StorageBackendVm.initialize (package:hive/src/backend/vm/storage_backend_vm.dart:82:30) #8 BoxBaseImpl.initialize (package:hive/src/box/box_base_impl.dart:90:20) #9 HiveImpl._openBox (package:hive/src/hive_impl.dart:106:22) #10 HiveImpl.openBox (package:hive/src/hive_impl.dart:135:18) #11 HiveProvider.openBox (package:fluent_life_flutter/db/hive_provider.dart:26:16) #12 main (package:fluent_life_flutter/main.dart:15:22) #13 _runMainZoned.. (dart:ui/hooks.dart:231:25) #14 _rootRun (dart:async/zone.dart:1190:13) #15 _CustomZone.run (dart:async/zone.dart:1093:19) #16 _runZoned (dart:async/zone.dart:1630:10) #17 runZonedGuarded (dart:async/zone.dart:1618:12) #18 _runMainZoned. (dart:ui/hooks.dart:223:5) #19 _startIsolate. (dart:isolate-patch/isolate_patch.dart:301:19) #20 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
luis901101 commented 3 years ago

I had this exact same issue, in my case I created an adapter for the flutter math Point class which I used inside one of my business logic classes.

The adapter I first created was like this:

class PointAdapter extends TypeAdapter<Point> {
  @override
  final typeId = HiveUtils.POINT_TYPE_ID;

  @override
  Point read(BinaryReader reader) => Point(reader.read(0), reader.read(1));

  @override
  void write(BinaryWriter writer, Point obj) {
    writer
      ..writeByte(2)
      ..writeByte(0)
      ..write(obj.x)
      ..writeByte(1)
      ..write(obj.y);
  }
}

But the Point class is a flutter framework class and doesn't have @HiveField set for 'x' and 'y'... so the first time the app runs everything gets stored fine but after a hot restart the reader throws the RangeError exception.

Then I updated the adapter to this:

class PointAdapter extends TypeAdapter<Point> {
  @override
  final typeId = HiveUtils.POINT_TYPE_ID;

  @override
  Point read(BinaryReader reader) => Point(reader.readInt(), reader.readInt());

  @override
  void write(BinaryWriter writer, Point obj) {
    writer
      ..writeInt(obj.x)
      ..writeInt(obj.y);
  }
}

and everything works fine now.

vdor commented 3 years ago

I had the same issue. But the name of my hive box was about 30 characters long. I don't remember what's the length exactly.

I had changed the name to make it shorter and it helped

ddevoss commented 3 years ago

This probably isn't the problem for everybody, but I was running into this error when I was writing null values in my adapter. I think it was throwing off the pointer.

What I THINK was happening was I was saving an index of an item with writeInt(), but sometimes my objects didn't have the index set yet, so it was writing null. Then when I was reading them back with readInt(), it was reading my int value with wild results e.g. "-9038923489". Then the next read would result in this error because there were no terminating bytes for the String data it was trying to read.

I fixed this by changing my readInt() to just read() and my writeInt() to just write(). Not quite as clean, it'd be nice if there was some null handling built into those specific data type functions, but I can also do it on my end.

MoacirSchmidt commented 3 years ago

Well, that seems to be an important feature since when I change the structure of the hive class my users have to reinstall the app....

luis901101 commented 3 years ago

Well, that seems to be an important bug since when I change the structure of the hive class my users would have to reinstall the app....

Not necessarily, you could change the @HiveField(...) index of each changed field in your class (by changing the field index you are ensuring a different type of an existing field to be properly stored)... also if you have had drastically changed your class or classes structure you could just change your box name and app will load a completely new box next time it starts.

themisir commented 3 years ago

Well, that seems to be an important bug since when I change the structure of the hive class my users have to reinstall the app....

It's a known feature (not a bug) of serialization in software engineering. You have to be careful when modifying serializers (aka: adapters in hive). It's not a bug because it's how object serializers works. Try modifying some bytes of an executable files in your operation system and try running it. It will be probably crashed because OS couldn't understand executable binary.

If you need dynamic schemes, I would suggest storing your data in json files or checking updating a class part of hive documentation.

MoacirSchmidt commented 3 years ago

I edited my comment to use better words. You made an excellent work and I really appreciate that. Thank you very much

themisir commented 3 years ago

I edited my comment to use better words. You made an excellent work and I really appreciate that. Thank you very much

I think you didn't get what I meant. You have to follow those rules to update classes safely - without requiring re-installation. If you don't follow them then the updated adapter would not deserialize previously written data and throw RangeError.

In short, just increase HiveField id when changing field type or adding a new fields and never use removed field's IDs.

RobinLbt commented 3 years ago

I've tried all solutions on this feed, none of those worked.

But I've found a solution in my case, maybe this will help others.

I've migrated my project to null safety, and before that Hive was working properly and this error never appears. It's only after migrating my project + all the packages to null safety that the error appears.

I've to duplicate my project and try to find the error by elimination. Here is what was causing the problem:

I have one object extending HiveObject, let's call it "Village". Village has an instance of a class as a attribute, called "Person"

Person is an abstract class (BTW no need to put HiveType and HiveField for abstract classes, but you need to put them for classes that extend this abstract class).

One of the classes extending Person is intentionally empty. Let's call it "SubPerson":

@HiveType(typeId: 8)
class SubPerson extends Person {}

Well before migrating my project to null safety, build runner was generating adapters and the reader for SubPerson was like this:

  @override
  SubPerson read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return SubPerson();
  }

After migrating, build runner generated the same adapter but like this:

  @override
  SubPerson read(BinaryReader reader) {
    return SubPerson();
  }

The error was caused by this method. I've manually changed the read method to the old one, and everything works now.

@TheMisir you should take a look at this

themisir commented 3 years ago

@leisim isn't Hive itself skipping to the next Frame if bytes have not read?

themisir commented 3 years ago

I removed read and write stubs for empty classes after this issue https://github.com/hivedb/hive/issues/638. I might have to look at Hive internals to check what's going on.

luis901101 commented 3 years ago

@RobinLbt what about the void write(BinaryWriter writer, SubPerson obj) method after migration? I mean... if the write method doesn't write anything to the BinaryWriter then the migrated read should be fine as you posted… the problem would be if the writer writes something and the reader reads nothing... that way when the next object in your class tries to read it will not read the right byte...

themisir commented 3 years ago

@RobinLbt what about the void write(BinaryWriter writer, SubPerson obj) method after migration? I mean... if the write method doesn't write anything to the BinaryWriter then the migrated read should be fine as you posted… the problem would be if the writer writes something and the reader reads nothing... that way when the next object in your class tries to read it will not read the right byte...

Ah you're right. This issue will happen when you're using the model inside another model. Hadn't think that way.

agent3bood commented 3 years ago

I had this problem when changing the model shape (add new value). The data on disk still does not have the new value so it throw an error;

Workaround

extension HiveBinaryReaderExtension on BinaryReader {
  // Solve issue https://github.com/hivedb/hive/issues/424
  bool tryReadBool(bool defaultValue) {
    try {
      return readBool();
    } catch (e) {
      print(e);
    }
    return defaultValue;
  }
}
siddhantsatpute commented 2 years ago

Hello, @anandsubbu007 @themisir I've also faced this issue when my one of the auto-generated model class (TypeAdapter) is modified manually and also when the original model class is modified and auto-generated classes are not generated again. So when I run the command flutter packages pub run build_runner build, all my auto-generated classes are regenerated and it solves the error Unhandled Exception: RangeError: Not enough bytes available.

matsushitak commented 2 years ago

i have same issue happened when restart app in Android and iOS. i try this command but can't resolve.

flutter packages pub run build_runner build

matsushitak commented 2 years ago

I created custom TypeAdapter for Decimal. I changed writer.write to writer.writeString and resolved it !!

class DecimalAdapter extends TypeAdapter<Decimal> {
  @override
  final typeId = hiveDecimalTypeId;

  @override
  Decimal read(BinaryReader reader) {
    final str = reader.readString();
    return Decimal.tryParse(str)!;
  }

  @override
  void write(BinaryWriter writer, Decimal obj) {
    // writer.write(obj.toString()); <----- this.
    writer.writeString(obj.toString());
  }
}
roubachof commented 2 years ago

Same as @matsushitak very surprisingly, the method writer.write(xx) doesn't seem to handle rightly the given type. You have to use the specialized method or you will hit the RangeError mark.

themisir commented 2 years ago

Same as @matsushitak very surprisingly, the method writer.write(xx) doesn't seem to handle rightly the given type. You have to use the specialized method or you will hit the RangeError mark.

Well indeed, read/write and read$Type/write$Type does slightly different things. write(value) writes a byte representing type id of specific type before writing the data using write$Type method (you can set writeTypeId optional argument to false in order to disable this behavior). The written typeId byte is then used by read method to check which type is the following data and uses corresponding read$Type method to read the data.

The issues in your cases caused because you've written data using write() method which appends typeId before data bytes but, you've read that data using specific type reader (readString()) which doesn't relies on type id but instead understands written typeId value as part of length of the string (strings in hive encoded as length+bytes...) and then tries to read invalid amount of bytes, therefore throws RangeError.

roubachof commented 2 years ago

Thank you for the explanation! I added a warning in the docs to help people with this possible culprit.

roubachof commented 2 years ago

Just thinking, but it could be interesting to add a more complex scenario in the "manual adapter" chapter. Especially how would you write a adapter with a complex object having another complex object as a property.

saibotma commented 2 years ago

Thank you for the explanation! I added a warning in the docs to help people with this possible culprit.

@roubachof Can you link where you put the warning?

saibotma commented 2 years ago

Same as @matsushitak very surprisingly, the method writer.write(xx) doesn't seem to handle rightly the given type. You have to use the specialized method or you will hit the RangeError mark.

Well indeed, read/write and read$Type/write$Type does slightly different things. write(value) writes a byte representing type id of specific type before writing the data using write$Type method (you can set writeTypeId optional argument to false in order to disable this behavior). The written typeId byte is then used by read method to check which type is the following data and uses corresponding read$Type method to read the data.

The issues in your cases caused because you've written data using write() method which appends typeId before data bytes but, you've read that data using specific type reader (readString()) which doesn't relies on type id but instead understands written typeId value as part of length of the string (strings in hive encoded as length+bytes...) and then tries to read invalid amount of bytes, therefore throws RangeError.

@themisir Is there actually any reason why the behavior is different? And which is the preferred one for which use case?

themisir commented 2 years ago

Is there actually any reason why the behavior is different?

read and write methods used by hive itself for reading values because value type could be anything so this methods uses type ids to find out type of value so it can correctly deserialize it using specific writeType and readType methods.

And which is the preferred one for which use case?

read and write if you don't know runtime type of the value. But for custom adapters I would suggest using write$Type / read$Type methods as a kind of type safety measurement.

ShridharBanavasi1997 commented 2 years ago

The problem is in the generated adapter, Make sure you regenerate adapter if you changed hive object structer

zellidev0 commented 2 years ago

For me worked the following: (Disclaimer: I'm using hive together with freezed case classes.)

Take a look at the Adapter implementation.

For me it looked like that.

 @override
  _$PersistenceServiceModelDrawerConfigOrientationNorth read(
      BinaryReader reader) {
    return _$PersistenceServiceModelDrawerConfigOrientationNorth();
  }

But it should have looked like that.

@override
  _$PersistenceServiceModelDrawerConfigOrientationNorth read(
      BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return _$PersistenceServiceModelDrawerConfigOrientationNorth();
  }

Solution I had to add the json annotation method to the class. This made the generating of the correct adapters possible.

factory PersistenceServiceModelDrawerConfigOrientation.fromJson(
          Map<String, dynamic> json) =>
      _$PersistenceServiceModelDrawerConfigOrientationFromJson(json);
carlosaparadam commented 2 years ago

Hello, @anandsubbu007 @themisir I've also faced this issue when my one of the auto-generated model class (TypeAdapter) is modified manually and also when the original model class is modified and auto-generated classes are not generated again. So when I run the command flutter packages pub run build_runner build, all my auto-generated classes are regenerated and it solves the error Unhandled Exception: RangeError: Not enough bytes available.

Tanks @siddhantsatpute this solution it's work for me

towcar commented 1 year ago

Fixed this problem yesterday with flutter packages pub run build_runner build Problem returned the next morning. Spent a half day on this problem, after reading this similar issue - https://github.com/hivedb/hive/issues/943 - flutter clean fixed everything.

Edit: but then I did a re-build and the error is back. Error: RangeError: Not enough bytes available.

williamsko commented 1 year ago

this issue is solved when i delete local data.

I have the same problem. Each time I have to delete the local data. Have you managed to find a solution?

vijayvaghela72 commented 1 year ago

i am facing same issue not solve yet .

check many article and solution but still same .

vijayvaghela72 commented 1 year ago

Error: RangeError: Not enough bytes available.

due to this error package is useless for me .

astubenbord commented 1 year ago

I faced the same issue when using new sealed classes, or more specifically empty classes.

Assuming the following hierarchy:

sealed class A {
  const A();
}

@HiveType(typeId: 3)
class B extends A {
  const B();
}

@HiveType(typeId: 2)
class C extends A {
  final int field;
  const C(this.field)
}

The generated adapter for the empty class (here B) currently implements the read method as follows:

B read(BinaryReader reader) {
  return B();
}

However, the code should look as follows:

B read(BinaryReader reader) {
  reader.readyByte(); // Consume written byte
  return B();
}

Notice the added line reader.readByte(). This seems to be necessary since the write method writes a single byte (writer.writeByte(0)). By not "consuming" this written byte, the offsets seem to mismatch in following iterations.

This issue may also occur in other cases when the constructor parameters are not empty. There is also another issue #1081 which may be related.

ramaniOS0306 commented 9 months ago

I am getting the same error while launching the app second time. Any fix for this