Hive: HiveError: Cannot read, unknown typeId: 38. Did you forget to register an adapter?

Created on 4 Jun 2020  Â·  22Comments  Â·  Source: hivedb/hive

Steps to Reproduce

Previous code before the issue

The registration of the adapter:

registerAdapter(ShelfAdapter());
registerAdapter(ShelfProductAdapter());

My Models + Adapter:

@HiveType(typeId: 4)
class Product implements Identifiable {
  @HiveField(0)
  @override
  final String id;
  @HiveField(1)
  final String name;

  @HiveField(2)
  final ProductType type;

  const Product({
    @required this.id,
    @required this.name,
    @required this.type,
  });
}
part of 'product.dart';

// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************

class ProductAdapter extends TypeAdapter<Product> {
  @override
  final typeId = 4;

  @override
  Product read(BinaryReader reader) {
    var numOfFields = reader.readByte();
    var fields = <int, dynamic>{
      for (var i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return Product(
      id: fields[0] as String,
      name: fields[1] as String,
      type: fields[2] as ProductType,
    );
  }

  @override
  void write(BinaryWriter writer, Product obj) {
    writer
      ..writeByte(3)
      ..writeByte(0)
      ..write(obj.id)
      ..writeByte(1)
      ..write(obj.name)
      ..writeByte(2)
      ..write(obj.type);
  }
}
part 'product_type.g.dart';

@HiveType(typeId: 4)
class ProductType {

  @HiveField(0)
  final int value;

  const ProductType(this.value);
}
````

part of 'product_type.dart';

// ***********************
// TypeAdapterGenerator
//
***********************

class ProductTypeAdapter extends TypeAdapter {
@override
final typeId = 4;

@override
ProductType read(BinaryReader reader) {
var numOfFields = reader.readByte();
var fields = {
for (var i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return ProductType(fields[0] as int);
}

@override
void write(BinaryWriter writer, ProductType obj) {
writer
..writeByte(1)
..writeByte(0)
..write(obj.value);
}
}
```

So far, so good.
But I want to remove the child object / adapter because we don't need it from now on.
So let's completely remove the ProjectType and the ProjectTypeAdapter.

And not the App is crashing with the following Issue:

HiveError: Cannot read, unknown typeId: 38. Did you forget to register an adapter?

After a complete new installation everything is working fine.

Version

  • Platform: iOS, Android
  • Flutter version: 1.17.2 • channel stable
  • Package versions:

    • hive: ^1.4.1+1

    • hive_flutter: ^0.3.0+2

enhancement

Most helpful comment

I have this problem HiveError: Cannot read, unknown typeId: 38. Did you forget to register an adapter? what should I do?

Have you registered the adapter using Hive.registerAdapter(..)? The adapters must be registered before Hive.openBox(..) calls

All 22 comments

I'm not completely sure about why the type id 38 gets mentioned… Hive internally uses 32 reserved type ids, so your id 4 should have become 32 + 4 = 36.

More importantly, AFAIK the current Hive architecture doesn't allow for removing adapters. It essentially saves "now come some bytes that the adapter with id 38 knows how to decode and encode". Then it asks the adapter to decode the values – if the adapter is missing, Hive doesn't know how to continue and aborts parsing.

AFAIK the current Hive architecture doesn't allow for removing adapters

Exactly. Hive uses the adapter to determine how many bytes each entry uses. When an adapter is missing, Hive cannot find the following entry.

Sorry, my precious answer was wrong: The entry does contain the length and we can just add an Hive.ignoreTypeId(38) method.

I have the same problem, i think that there is something wrong cause when i used the typeId: 0 i get

HiveError: Cannot read, unknown typeId: 114.

for ids more than 0 i get the error on typeId 32

Any solution of this? I have typedId from 0 to 33 and error says: Cannot read, unknown typeId: 69. Did you forget to register an adapter?. I don't know what to do

Any solution of this? I have typedId from 0 to 33 and error says: Cannot read, unknown typeId: 69. Did you forget to register an adapter?. I don't know what to do

You have to add '@HiveType(typeId: 1)' at the top of you class name as you can see in this video https://www.youtube.com/watch?v=SFcMdQXnM78&t=619s at 10:19

I asked them to add it to the documentation before it wasnt there

Any solution of this? I have typedId from 0 to 33 and error says: Cannot read, unknown typeId: 69. Did you forget to register an adapter?. I don't know what to do

You have to add '@HiveType(typeId: 1)' at the top of you class name as you can see in this video https://www.youtube.com/watch?v=SFcMdQXnM78&t=619s at 10:19

I asked them to add it to the documentation before it wasnt there

I've already done that. My code was working, but now is showing that error

the only thing that i can think of is to try "flutter clean cache" or try to move from channel master to stable

AFAIK the current Hive architecture doesn't allow for removing adapters

Exactly. ~Hive uses the adapter to determine how many bytes each entry uses. When an adapter is missing, Hive cannot find the following entry.~

Sorry, my precious answer was wrong: The entry does contain the length and we can just add an Hive.ignoreTypeId(38) method.

But we need to know how many bytes should we skip before reading next frame? Also some adapters might write variable length data. So using something like: Hive.ignoreTypeId(38, length: 8) - will not work too.

@TheMisir The first four bytes of any frame are the frame length so knowledge about the adapter is not needed to skip a frame.

Thanks, @leisim. I'll add HiveImpl.ignoreTypeId function asap.

I have this problem HiveError: Cannot read, unknown typeId: 38. Did you forget to register an adapter? what should I do?

I have this problem HiveError: Cannot read, unknown typeId: 38. Did you forget to register an adapter? what should I do?

Have you registered the adapter using Hive.registerAdapter(..)? The adapters must be registered before Hive.openBox(..) calls

Yes it was working before I've updated flutter to 1.20 after the update I've updated hive to 1.4.2 before that it was 1.4.1+1 and suddenly this error occurs.

I've done flutter clean cache. Still getting the error.

My error comes after second launch when I populate the box with data. At first launch I create the box and register the adapters as well and when I go to a specific page the box will get populated with data and I get no error. But in the second run when the app want's to read the data from the box this error shows up.

My error comes after second launch when I populate the box with data. At first launch I create the box and register the adapters as well and when I go to a specific page the box will get populated with data and I get no error. But in the second run when the app want's to read the data from the box this error shows up.

What you can do after following the previous advices is try to delete the created db and create a new one, me when i change database name after flutter clean worked

My init path is final appDocumentDirectory = await getApplicationSupportDirectory();. If I clear data the app the database shouldn't be deleted? Maybe the path_provider is causing the problem? 🤔

I've updated path_provider from 1.6.10 to 1.6.11 and boom, problem has gone away.

Looks like this issue is still happening. After adding a new case to my enum, hive throws this error when reading a class that has this enum property.

HiveError: Cannot read, unknown typeId: 62. Did you forget to register an adapter?

I tried calling ignoreTypeId<dynamic>(62); but this didn't help.
@leisim

@TheMisir I ran into some troubles using ignoreTypeId and starting digging into the source code of your pull request https://github.com/hivedb/hive/pull/397

It seems that the BinaryWriterImpl uses findAdapterForValue to find the _ResolvedAdapter.

Which - if I'm not mistaken - means ignoreTypeId<T>(int typeId) results in

  1. ignored reads from the typeId passed
  2. ignored writes for any object matching following code:
    bool matches(dynamic value) => value is T;

This makes that when using the method without generics:
Hive.ignoreTypeId(0)
all writes will be ignored, as anything is dynamic will always be true and return the IgnoredTypeAdapter.
Does this mean you cannot delete the Hive-object from your class structure, because you need to pass it as a generics argument?

The name of the method is kind of misleading as it makes it seem just passing a typeId is fine. Furthermore, not passing a generics Type seems like a very easy mistake which results in very weird behaviour where:

  • any value is overwritten with null when being written, also the typeId is set to the typeId of the IgnoredTypeAdapter
  • reading the values of a box afterwards returns all null values, IgnoredTypeAdapter is used as well because the write set the typeId to the ignored one

We managed to work around this by calling:
Hive.ignoreTypeId<RandomClass>(0)
which

  • prevents us from registering typeId 0 again
  • ignores reads for typeId 0
  • ignores writes for RandomClass which is a dummy non-Hive class anyway

If you need more information, please let me know.

I'm not sure what the best fix for this would be. A mention of this problem in the documentation of ignoreTypeId would be very helpful in any case.

@TheMisir I ran into some troubles using ignoreTypeId and starting digging into the source code of your pull request #397

It seems that the BinaryWriterImpl uses findAdapterForValue to find the _ResolvedAdapter.

Which - if I'm not mistaken - means ignoreTypeId<T>(int typeId) results in

  1. ignored reads from the typeId passed
  2. ignored writes for any object matching following code:
    bool matches(dynamic value) => value is T;

This makes that when using the method without generics:
Hive.ignoreTypeId(0)
all writes will be ignored, as anything is dynamic will always be true and return the IgnoredTypeAdapter.
Does this mean you cannot delete the Hive-object from your class structure, because you need to pass it as a generics argument?

The name of the method is kind of misleading as it makes it seem just passing a typeId is fine. Furthermore, not passing a generics Type seems like a very easy mistake which results in very weird behaviour where:

  • any value is overwritten with null when being written, also the typeId is set to the typeId of the IgnoredTypeAdapter
  • reading the values of a box afterwards returns all null values, IgnoredTypeAdapter is used as well because the write set the typeId to the ignored one

We managed to work around this by calling:
Hive.ignoreTypeId<RandomClass>(0)
which

  • prevents us from registering typeId 0 again
  • ignores reads for typeId 0
  • ignores writes for RandomClass which is a dummy non-Hive class anyway

If you need more information, please let me know.

I'm not sure what the best fix for this would be. A mention of this problem in the documentation of ignoreTypeId would be very helpful in any case.

Thanks for letting me know. I could write a type check to ignore (don't use for writes) adapters if T == dynamic so calling ignoreTypeId(0) will just ignore reading typeId == 0 fields / entries but will not be used for write operations.

Hi TheMisir,

Thanks for the quick answer.
I think that's a good improvement!

I was just wondering, is it even necessary to have the generic parameter here? If you don't want to use a certain typeId anymore, the IgnoredTypeAdapter will do just fine without it (it'll prevent registering the same typeId).
As of now, it only impacts writing, but is it ever desired behaviour to just ignore all writes of a certain Type? It seems like a case you would want to get a HiveError for because you're still using a class that have been deprecated.

I understand that that would be a bigger/breaking change, and your suggested fix will work fine for us as well.
If you want an extra set of eyes or hands for discussion / review / testing / coding, happy to help!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SergeShkurko picture SergeShkurko  Â·  4Comments

sergiyvergun picture sergiyvergun  Â·  4Comments

juandiago picture juandiago  Â·  4Comments

jamesdixon picture jamesdixon  Â·  3Comments

NourEldinShobier picture NourEldinShobier  Â·  3Comments