Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
anandsubbu007 opened this issue Sep 6, 2020 · 50 comments
Open

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

anandsubbu007 opened this issue Sep 6, 2020 · 50 comments
Assignees
Labels
problem An unconfirmed bug.

Comments

@anandsubbu007
Copy link

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.
�[38;5;248mE/flutter (20626): #0      BinaryReaderImpl._requireBytes�[39;49m
�[38;5;248mE/flutter (20626): #1      BinaryReaderImpl.readByte�[39;49m
�[38;5;248mE/flutter (20626): #2      StaticModelAdapter.read�[39;49m
�[38;5;248mE/flutter (20626): #3      BinaryReaderImpl.read�[39;49m
�[38;5;248mE/flutter (20626): #4      BinaryReaderImpl.readFrame�[39;49m
�[38;5;248mE/flutter (20626): #5      FrameHelper.framesFromBytes�[39;49m
�[38;5;248mE/flutter (20626): #6      FrameIoHelper.framesFromFile�[39;49m
E/flutter (20626): <asynchronous suspension>
�[38;5;248mE/flutter (20626): #7      StorageBackendVm.initialize�[39;49m
E/flutter (20626): <asynchronous suspension>
�[38;5;248mE/flutter (20626): #8      BoxBaseImpl.initialize�[39;49m
�[38;5;248mE/flutter (20626): #9      HiveImpl._openBox�[39;49m
E/flutter (20626): <asynchronous suspension>
�[38;5;248mE/flutter (20626): #10     HiveImpl.openBox�[39;49m
�[38;5;248mE/flutter (20626): #11     main�[39;49m
E/flutter (20626): <asynchronous suspension>
�[38;5;244mE/flutter (20626): #12     _runMainZoned.<anonymous closure>.<anonymous closure>  (dart:ui/hooks.dart:231:25)�[39;49m
�[38;5;244mE/flutter (20626): #13     _rootRun  (dart:async/zone.dart:1190:13)�[39;49m
�[38;5;244mE/flutter (20626): #14     _CustomZone.run  (dart:async/zone.dart:1093:19)�[39;49m
�[38;5;244mE/flutter (20626): #15     _runZoned  (dart:async/zone.dart:1630:10)�[39;49m
�[38;5;244mE/flutter (20626): #16     runZonedGuarded  (dart:async/zone.dart:1618:12)�[39;49m
�[38;5;244mE/flutter (20626): #17     _runMainZoned.<anonymous closure>  (dart:ui/hooks.dart:223:5)�[39;49m
�[38;5;244mE/flutter (20626): #18     _startIsolate.<anonymous closure>  (dart:isolate-patch/isolate_patch.dart:301:19)�[39;49m
�[38;5;244mE/flutter (20626): #19     _RawReceivePortImpl._handleMessage  (dart:isolate-patch/isolate_patch.dart:168:12)�[39;49m
E/flutter (20626):
E/flutter (20626): [ERROR:flutter/lib/ui/ui_dart_state.cc(171)] Unhandled Exception: RangeError: Not enough bytes available.
�[38;5;248mE/flutter (20626): #0      BinaryReaderImpl._requireBytes�[39;49m
�[38;5;248mE/flutter (20626): #1      BinaryReaderImpl.readByte�[39;49m
�[38;5;248mE/flutter (20626): #2      StaticModelAdapter.read�[39;49m
�[38;5;248mE/flutter (20626): #3      BinaryReaderImpl.read�[39;49m
�[38;5;248mE/flutter (20626): #4      BinaryReaderImpl.readFrame�[39;49m
�[38;5;248mE/flutter (20626): #5      FrameHelper.framesFromBytes�[39;49m
�[38;5;248mE/flutter (20626): #6      FrameIoHelper.framesFromFile�[39;49m
E/flutter (20626): <asynchronous suspension>
�[38;5;248mE/flutter (20626): #7      StorageBackendVm.initialize�[39;49m
E/flutter (20626): <asynchronous suspension>
�[38;5;248mE/flutter (20626): #8      BoxBaseImpl.initialize�[39;49m
�[38;5;248mE/flutter (20626): #9      HiveImpl._openBox�[39;49m
E/flutter (20626): <asynchronous suspension>
�[38;5;248mE/flutter (20626): #10     HiveImpl.openBox�[39;49m
�[38;5;248mE/flutter (20626): #11     main�[39;49m
E/flutter (20626): <asynchronous suspension>
�[38;5;244mE/flutter (20626): #12     _runMainZoned.<anonymous closure>.<anonymous closure>  (dart:ui/hooks.dart:231:25)�[39;49m
�[38;5;244mE/flutter (20626): #13     _rootRun  (dart:async/zone.dart:1190:13)�[39;49m
�[38;5;244mE/flutter (20626): #14     _CustomZone.run  (dart:async/zone.dart:1093:19)�[39;49m
�[38;5;244mE/flutter (20626): #15     _runZoned  (dart:async/zone.dart:1630:10)�[39;49m
�[38;5;244mE/flutter (20626): #16     runZonedGuarded  (dart:async/zone.dart:1618:12)�[39;49m
�[38;5;244mE/flutter (20626): #17     _runMainZoned.<anonymous closure>  (dart:ui/hooks.dart:223:5)�[39;49m
�[38;5;244mE/flutter (20626): #18     _startIsolate.<anonymous closure>  (dart:isolate-patch/isolate_patch.dart:301:19)�[39;49m
�[38;5;244mE/flutter (20626): #19     _RawReceivePortImpl._handleMessage  (dart:isolate-patch/isolate_patch.dart:168:12)�[39;49m
E/flutter (20626):

@anandsubbu007 anandsubbu007 added the problem An unconfirmed bug. label Sep 6, 2020
@themisir
Copy link
Contributor

themisir commented Sep 6, 2020

Could you reproduce the issue?

@anandsubbu007
Copy link
Author

this issue is solved when i delete local data.

@anandsubbu007
Copy link
Author

anandsubbu007 commented Sep 7, 2020

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

@anandsubbu007 anandsubbu007 reopened this Sep 7, 2020
@themisir
Copy link
Contributor

themisir commented Sep 7, 2020

Did the issue happened after changing model structure or randomly?

@anandsubbu007
Copy link
Author

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

@artem-bakuta
Copy link

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

@themisir
Copy link
Contributor

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

Could you share code with us to identify cause?

@anandsubbu007
Copy link
Author

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

@artem-bakuta
Copy link

artem-bakuta commented Oct 14, 2020

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
Copy link

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

any find the problem
#flutterhive

@Dimoshka
Copy link

Dimoshka commented Jan 3, 2021

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
Copy link

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
Copy link
Contributor

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
Copy link

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

@cosmotek
Copy link

cosmotek commented Feb 5, 2021

@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
Copy link
Member

simc commented Feb 5, 2021

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

@syedfaisaljaved
Copy link

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
Copy link

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
Copy link

vdor commented Mar 30, 2021

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
Copy link

ddevoss commented Apr 15, 2021

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
Copy link

MoacirSchmidt commented Apr 22, 2021

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
Copy link

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
Copy link
Contributor

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
Copy link

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

@themisir
Copy link
Contributor

themisir commented Apr 23, 2021

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.

  • Don't change the field numbers for any existing fields.
  • If you add new fields, any objects written by the "old" adapter can still be read by the new adapter. These fields are just ignored. Similarly, objects written by your new code can be read by your old code: the new field is ignored when parsing.
  • Fields can be renamed and even changed from public to private or vice versa as long as the field number stays the same.
  • Fields can be removed, as long as the field number is not used again in your updated class.
  • Changing the type of a field is not supported. You should create a new one instead.

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

@RobinLbt
Copy link

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
Copy link
Contributor

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

@themisir
Copy link
Contributor

I removed read and write stubs for empty classes after this issue #638. I might have to look at Hive internals to check what's going on.

@luis901101
Copy link

luis901101 commented May 13, 2021

@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
Copy link
Contributor

@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
Copy link

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
Copy link

siddhantsatpute commented Oct 18, 2021

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
Copy link

matsushitak commented Nov 24, 2021

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
Copy link

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
Copy link

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
Copy link
Contributor

themisir commented Dec 4, 2021

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
Copy link

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

@roubachof
Copy link

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
Copy link
Contributor

saibotma commented Mar 11, 2022

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
Copy link
Contributor

saibotma commented Mar 11, 2022

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
Copy link
Contributor

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
Copy link

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

@zellidev0
Copy link

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
Copy link

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
Copy link

towcar commented Oct 18, 2022

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 - #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
Copy link

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
Copy link

i am facing same issue not solve yet .

check many article and solution but still same .

@vijayvaghela72
Copy link

Error: RangeError: Not enough bytes available.

due to this error package is useless for me .

@astubenbord
Copy link

astubenbord commented Oct 6, 2023

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
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
problem An unconfirmed bug.
Projects
None yet
Development

No branches or pull requests