Specifying properties with multi-tenancy causes bug

Description

When I just specify multi-tenancy, all my insert / updates work.

However, when I just add properties to the schema declaration, I start to get this error:

weaviate.exceptions.UnexpectedStatusCodeError: Object was not updated.! Unexpected status code: 422, with response body: {‘error’: [{‘message’: ‘msg:repo.object code:422 err:search index nodes: class Nodes has multi-tenancy disabled, but request was with tenant’}]}.

This is the code:

nodes_collection = client.collections.create(
		name="Nodes",
		vectorizer_config=wvc.config.Configure.Vectorizer.none(),
		vector_index_config=Configure.VectorIndex.hnsw(
			distance_metric=VectorDistances.COSINE
		),
		# Multi tenancy to separate each user's data
		multi_tenancy_config=Configure.multi_tenancy(enabled=True, auto_tenant_creation=True, auto_tenant_activation=True),
		# Specify some properties beforehand to set right data type (i.e. obj[] instead of string[])
		properties=[
			Property(name="tags", data_type=DataType.OBJECT_ARRAY),
		]
	)

If I remove the properties field, then it will work again.

This is an example insert code:

def get_tenant_collection(name):
	try:
		return nodes_collection.with_tenant(name)
	except:
		nodes_collection.tenants.create(name)
		return nodes_collection.with_tenant(name)

tenant_collection = get_tenant_collection(tenant_name)
	
tenant_collection.data.insert(
	vector=record.vector,
	properties=record.properties,
	uuid=record.uniqueid
)

Even update / delete, all operations trigger the multi-tenancy error. I can confirm the rest of the code is working including getting the tenant collection because just commenting out properties, will make everything start working

nodes_collection = client.collections.create(
		name="Nodes",
		vectorizer_config=wvc.config.Configure.Vectorizer.none(),
		vector_index_config=Configure.VectorIndex.hnsw(
			distance_metric=VectorDistances.COSINE
		),
		# Multi tenancy to separate each user's data
		multi_tenancy_config=Configure.multi_tenancy(enabled=True, auto_tenant_creation=True, auto_tenant_activation=True),
		# Commenting this out makes all operations work again
		# properties=[
		# 	Property(name="tags", data_type=DataType.OBJECT_ARRAY),
		# ]
	)

Server Setup Information

  • Weaviate Server Version: Cloud
  • Multi Node? Number of Running Nodes: No
  • Client Language and Version: Python v4
  • Multitenancy?: Yes

hi @Tejas_Sharma !!

I believe you are facing this issue:

Please, make sure to leave a :+1: on that issue so we can prioritize it.

THanks!

Hi @DudaNogueira ,

I think mine is completely different because their bug is about multi-tenant to non-tenant but mine is that there is a bug in the SDK that if both multi tenancy and properties are specified, then everything breaks

Oh, sorry.

Do you think you can create a reproducible python code?

With that we better understand the issue by reproducing or fixing any code or assumptions along the way.

That issue has a python code that can server as starting point.

Thanks!

Okay thanks Duda, will try to get it out soon

Hi @DudaNogueira , aplogies for the delay, here’s the minimal reproducible code:

import uuid
import weaviate
import weaviate.classes as wvc
from weaviate.classes.query import Filter, MetadataQuery
from weaviate.classes.config import Configure, VectorDistances, Property, DataType
from weaviate.classes.tenants import Tenant
from datetime import datetime, timedelta
import pytz

try:
	# TODO: use different credentials for production
	# Best practice: store your credentials in environment variables
	wcd_url = ""
	wcd_api_key = ""

	client = weaviate.connect_to_weaviate_cloud(
		cluster_url=wcd_url,                                    # Replace with your Weaviate Cloud URL
		auth_credentials=wvc.init.Auth.api_key(wcd_api_key),    # Replace with your Weaviate Cloud key
	)
except Exception as e:
	print(e)
	# exit
	pass


try:
	# For all objects
	nodes_collection = client.collections.create(
		name="Nodes",
		vectorizer_config=wvc.config.Configure.Vectorizer.none(),
		vector_index_config=Configure.VectorIndex.hnsw(
			distance_metric=VectorDistances.COSINE
		),
		# Multi tenancy to separate each user's data
		multi_tenancy_config=Configure.multi_tenancy(enabled=True, auto_tenant_creation=True, auto_tenant_activation=True),
		inverted_index_config=Configure.inverted_index( 
			index_null_state=True,
        	index_property_length=True,
			index_timestamps=True
		)
		# Specify some properties beforehand to set right data type (i.e. obj[] instead of string[])
		properties=[
			Property(name="tags", data_type=DataType.OBJECT_ARRAY),
		]
	)
except:
	nodes_collection = client.collections.get("Nodes")

try:
	# Create tenant on Node
	nodes_collection.tenants.create(
		tenants=[
			Tenant(name="tenantA"),
			Tenant(name="tenantB"),
		]
	)
except:
	pass


# Will cause an error
nodes_collection.with_tenant('tenantA').data.insert(
	vector=[0.0] * 384,
	properties={'lastUpdateDeviceId': 'device-78C24351-F40A-4E37-8953-F003FA474877'},
	uuid=str(uuid.uuid4())
)

Hi @Tejas_Sharma !!

You need to specify at least one nested property if using the object. Also, there was a missing , in your code, right after inverted_index_config

Here is a working example:

import uuid
import weaviate
import weaviate.classes as wvc
from weaviate.classes.query import Filter, MetadataQuery
from weaviate.classes.config import Configure, VectorDistances, Property, DataType
from weaviate.classes.tenants import Tenant
from datetime import datetime, timedelta
import pytz

# For all objects
client.collections.delete("Test")
nodes_collection = client.collections.create(
    name="Test",
    vectorizer_config=wvc.config.Configure.Vectorizer.none(),
    vector_index_config=Configure.VectorIndex.hnsw(
        distance_metric=VectorDistances.COSINE
    ),
    # Multi tenancy to separate each user's data
    multi_tenancy_config=Configure.multi_tenancy(enabled=True, auto_tenant_creation=True, auto_tenant_activation=True),
    inverted_index_config=Configure.inverted_index( 
        index_null_state=True,
        index_property_length=True,
        index_timestamps=True
    ),
    # Specify some properties beforehand to set right data type (i.e. obj[] instead of string[])
    properties=[
        wvc.config.Property(
            name="tags",
            data_type=wvc.config.DataType.OBJECT,
            nested_properties=[
                wvc.config.Property(
                    name="sub_property1",
                    data_type=wvc.config.DataType.TEXT
                ),
                wvc.config.Property(
                    name="sub_property2",
                    data_type=wvc.config.DataType.INT
                )
            ]
        )
    ]
)


# Create tenant on Node
nodes_collection.tenants.create(
    tenants=[
        Tenant(name="tenantA"),
        Tenant(name="tenantB"),
    ]
)

# Will cause an error
nodes_collection.with_tenant('tenantA').data.insert(
	vector=[0.0] * 384,
	properties={
        'lastUpdateDeviceId': 'device-78C24351-F40A-4E37-8953-F003FA474877',
        "tags": {"sub_property1": "somedata", "sub_property2": 123}        
    },
	uuid=str(uuid.uuid4())
)

Let me know if this helps.

Thanks!

1 Like

Ah okay, thanks Duda. We actually found a workaround solution of just creating the first record with tags specified to prevent this error but will try this out in the future.

I would like to add though that it would help if it specified that error during the node creation rather than the multi tenancy error since the error it was giving was not related to the fix and would thus be hard to debug

Oh, I see. This is a pitfall of the AUTOSCHEMA_ENABLED feature.

Note that we do not recommend leaving AUTOSCHEMA_ENABLED in production as it can create new properties if you specify a wrong property name.

If you have AUTOSCHEMA_ENABLED and do not specify a property at collection creation, the first property inserted will change your schema for you.

This code will fail on collection creation, and not on tenant creation:

nodes_collection = client.collections.create(
    name="Nodes",
    vectorizer_config=wvc.config.Configure.Vectorizer.none(),
    vector_index_config=Configure.VectorIndex.hnsw(
        distance_metric=VectorDistances.COSINE
    ),
    # Multi tenancy to separate each user's data
    multi_tenancy_config=Configure.multi_tenancy(enabled=True, auto_tenant_creation=True, auto_tenant_activation=True),
    inverted_index_config=Configure.inverted_index( 
        index_null_state=True,
        index_property_length=True,
        index_timestamps=True
    ),
    # Specify some properties beforehand to set right data type (i.e. obj[] instead of string[])
    properties=[
        Property(name="tags", data_type=DataType.OBJECT_ARRAY),
    ]
)

error message:

UnexpectedStatusCodeError: Collection may not have been created properly.! Unexpected status code: 422, with response body: {‘error’: [{‘message’: “Property ‘tags’: At least one nested property is required for data type object/object”}]}.

1 Like