{"record":{"id":"08cac9efa3cd4549","repo":"weaviate/weaviate","slug":"invalid-tenant-shard-q-expected-q","errorCode":null,"errorMessage":"invalid tenant shard %q, expected %q","messagePattern":"invalid tenant shard %q, expected %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cluster/router/router.go","lineNumber":662,"sourceCode":"\n\torderedReplicas := sort(readReplicas.Replicas, preferredNode(params.DirectCandidateNode, r.nodeSelector.LocalName()))\n\n\treturn types.ReadRoutingPlan{\n\t\tLocalHostname: r.nodeSelector.LocalName(),\n\t\tShard:         params.Shard,\n\t\tTenant:        params.Tenant,\n\t\tReplicaSet: types.ReadReplicaSet{\n\t\t\tReplicas: orderedReplicas,\n\t\t},\n\t\tConsistencyLevel:    params.ConsistencyLevel,\n\t\tIntConsistencyLevel: cl,\n\t}, nil\n}\n\n// validateTenantShard validates that the tenant and shard are consistent.\nfunc (r *multiTenantRouter) validateTenantShard(tenant, shard string) error {\n\tif shard != \"\" && tenant != \"\" && shard != tenant {\n\t\treturn fmt.Errorf(\"invalid tenant shard %q, expected %q\", shard, tenant)\n\t}\n\n\treturn nil\n}\n\n// BuildRoutingPlanOptions constructs routing plan options for multi-tenant collections.\nfunc (r *multiTenantRouter) BuildRoutingPlanOptions(tenant, shard string, cl types.ConsistencyLevel, directCandidate string) types.RoutingPlanBuildOptions {\n\treturn types.RoutingPlanBuildOptions{\n\t\tShard:               shard,\n\t\tTenant:              tenant,\n\t\tConsistencyLevel:    cl,\n\t\tDirectCandidateNode: directCandidate,\n\t}\n}\n\n// tenantShard normalizes the shard parameter by using the tenant name as the shard\n// if no explicit shard is provided, as required in multi-tenant mode.\nfunc tenantShard(shard string, tenant string) string {","sourceCodeStart":644,"sourceCodeEnd":680,"githubUrl":"https://github.com/weaviate/weaviate/blob/75aa4b6d11f8818305aafd4440b4e32794f7ca04/cluster/router/router.go#L644-L680","documentation":"multiTenantRouter.validateTenantShard rejects a routing request where an explicit shard identifier does not match the tenant it was paired with. In multi-tenant collections each tenant owns exactly one shard, so shard names are derived from tenant names; passing both with different values indicates a caller bug or stale metadata. The check only fires when both values are non-empty.","triggerScenarios":"Calling GetReadWriteReplicasLocation, GetWriteReplicasLocation, or GetReadReplicasLocation with a tenant and a shard string that differ, e.g. tenant=\"User-A\" shard=\"User-B\" or a hand-built shard name.","commonSituations":"Custom tooling that maps old shard names to tenants after a migration; clients caching a shard name from before a tenant rename; code concatenating collection/shard names incorrectly; replication scripts addressing shards directly.","solutions":["Pass only the tenant and let the router resolve the shard itself (omit/empty the shard parameter).","Verify the shard name equals the tenant name for multi-tenant collections; use the schema/tenants API to list correct tenant names.","Refresh any cached tenant->shard mapping after tenant create/rename/delete operations."],"exampleFix":"// before\nloc, err := router.GetReadWriteReplicasLocation(ctx, class, \"tenant-1\", \"tenant-1_shard0\", ...)\n// after\nloc, err := router.GetReadWriteReplicasLocation(ctx, class, \"tenant-1\", \"\", ...) // shard resolved from tenant","handlingStrategy":"validation","validationCode":"func validateTenantShard(tenant, shard string) error {\n\tif shard != \"\" && tenant != \"\" && shard != tenant {\n\t\treturn fmt.Errorf(\"shard %q does not match tenant %q\", shard, tenant)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass only the tenant for multi-tenant collections and let the router derive the shard.","Never hand-build shard names; fetch tenants via the schema API.","Invalidate cached tenant->shard mappings after tenant lifecycle operations."],"tags":["multi-tenancy","routing","validation"],"backgroundTag":"tenant-shard-mismatch","analyzedSha":"75aa4b6d11f8818305aafd4440b4e32794f7ca04","analyzedAt":"2026-09-04T14:58:20.392Z","contentChangedAt":"2026-09-04T14:58:20.392Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}