Repository navigation
Using forSchemaOptions inside forSchema causes a duplicate type name error #294
Description
Activity
Just to be clear if I don't pass any options at all - not an empty object - nothing at all, I don't get this error and get errors when trying to actually work with the long (which is a bit later I think)
Hi @alonisser. It looks like the issue comes from reusing options within the schema registry library. When an options object is passed in to
Type.forSchema(even empty), itsregistrykey will be populated with the newly instantiated types. This state persists between calls and will trigger aduplicate type nameerror when a later call tries to instantiate a type already registered.Due to this behavior, it's best to pass in new options when calling
Type.forSchemaon unrelated schemas. A possible solution for libraries wrappingavscis to allow users to provide the parsing function itself, defaulting toType.forSchema. TheparseHookoption inBlockDecoderis an example of this. Here, it sounds like this would require a change to the schema library, which I would encourage you to suggest.In the meantime, I think you can work around the error by adding a
typeHookto the options. This hook will intercept the type generation logic, checking first if a type with the same name is already registered and returning it directly if so. For example something like:// Hook to add as `typeHook` key to `Type.forSchema` options. function typeHook(schema, opts) { let name = schema.name; if (!name) { return; // Not a named type, use default logic. } if (!~name.indexOf('.')) { // We need to qualify the type's name. const namespace = schema.namespace || opts.namespace; if (namespace) { name = `${namespace}.${name}`; } } // Return the type registered with the same name, if any. return opts.registry[name]; }
Let me know if this works for your use-case.
Reacted by Petr TatarinovThanks for the reply @mtth I'm trying to work with the schemalibrary lib, but currently can't get traction there.
I've tried a direct typehook and failed to make it work, I'll try this and updateThanks, it worked!
Sorry to resurrect this, but will the same duplication problem happen if I'm trying to pass in logicalTypes as an option instead of registry? I feel like it might but I'm having trouble stepping through and seeing where "the state is persisted between calls" like you mentioned!
Thanks for any help :)
Reacted by Alex RichardsonHi @NicholasGWK. Assuming you are using the same underlying library, you will face the issue described above as soon as you specify options. The state is persisted in the options object itself: when non-
undefined, it will gain aregistryattribute which spans calls.That being said, the
typeHooksnippet in #294 (comment) should allow you to work around it:const opts = { logicalTypes: {}, // Your logical types. typeHook, // The typehook from the comment above. // Any other options... };
I'm using avsc wrapped by schemaregistry Thanks for your hard word and good docs!
I'm trying to solve the long/bigint issue with the constraint I have only limited access directly to avsc. the wrapping library allows me to pass a
forSchemaOptionsconfiguration that is passed inside into an avsc wrapper and then invokedI've found out that passing inside forSchemaOptions
{
registry: { long: longType } //Where longType is bigInt based long.__with as the docs refer to
}
But I've encountered a peculiar problem. if I pass a forSchemaOptions object with the registry or even an empty object
{}without a registryI get ONCE this error (the actual key is part of the schema auto generated by debezium/kafkaconnect)
How can we work around this?