{"record":{"id":"90055160b516ba46","repo":"weaviate/weaviate","slug":"tenant-s-not-found-when-it-should-have-been","errorCode":null,"errorMessage":"tenant '%s' not found when it should have been","messagePattern":"tenant '(.+?)' not found when it should have been","errorType":"http","errorClass":null,"httpStatus":422,"severity":"warning","filePath":"adapters/handlers/rest/handlers_schema.go","lineNumber":630,"sourceCode":"\t\t\treturn schema.NewTenantsGetOneNotFound()\n\t\t}\n\t\tif errors.Is(err, schemaUC.ErrUnexpectedMultiple) {\n\t\t\treturn schema.NewTenantsGetOneInternalServerError().\n\t\t\t\tWithPayload(errPayloadFromSingleErr(principal, err))\n\t\t}\n\t\tswitch {\n\t\tcase errors.As(err, &authzerrors.Forbidden{}):\n\t\t\treturn schema.NewTenantsGetOneForbidden().\n\t\t\t\tWithPayload(errPayloadFromSingleErr(principal, err))\n\t\tdefault:\n\t\t\treturn schema.NewTenantsGetOneUnprocessableEntity().\n\t\t\t\tWithPayload(errPayloadFromSingleErr(principal, err))\n\t\t}\n\t}\n\tif tenant == nil {\n\t\ts.metricRequestsTotal.logUserError(params.ClassName)\n\t\treturn schema.NewTenantsGetOneUnprocessableEntity().\n\t\t\tWithPayload(errPayloadFromSingleErr(principal, fmt.Errorf(\"tenant '%s' not found when it should have been\", params.TenantName)))\n\t}\n\ts.metricRequestsTotal.logOk(params.ClassName)\n\treturn schema.NewTenantsGetOneOK().WithPayload(tenant)\n}\n\nfunc (s *schemaHandlers) tenantExists(params schema.TenantExistsParams, principal *models.Principal) middleware.Responder {\n\tctx := restCtx.AddPrincipalToContext(params.HTTPRequest.Context(), principal)\n\tif err := s.manager.ConsistentTenantExists(ctx, principal, params.ClassName, *params.Consistency, params.TenantName); err != nil {\n\t\ts.metricRequestsTotal.logError(params.ClassName, err)\n\t\tif errors.Is(err, schemaUC.ErrNotFound) {\n\t\t\treturn schema.NewTenantExistsNotFound()\n\t\t}\n\t\tswitch {\n\t\tcase errors.As(err, &authzerrors.Forbidden{}):\n\t\t\treturn schema.NewTenantExistsForbidden().\n\t\t\t\tWithPayload(errPayloadFromSingleErr(principal, err))\n\t\tdefault:\n\t\t\treturn schema.NewTenantExistsUnprocessableEntity().","sourceCodeStart":612,"sourceCodeEnd":648,"githubUrl":"https://github.com/weaviate/weaviate/blob/75aa4b6d11f8818305aafd4440b4e32794f7ca04/adapters/handlers/rest/handlers_schema.go#L612-L648","documentation":"Weaviate's GET /v1/schema/{className}/tenants/{tenantName} handler fetched the tenant via GetConsistentTenant without error, but the returned tenant object was nil. Since the schema manager already maps genuinely missing tenants to a 404 (schemaUC.ErrNotFound), reaching this path means an unexpected nil result — an internal invariant violation rather than a normal 'not found' response. The handler returns 422 with this message to surface the inconsistency instead of nil-dereferencing.","triggerScenarios":"Calling GET /v1/schema/{class}/tenants/{tenant} where GetConsistentTenant returns (nil, nil). This indicates a race (tenant removed between lookup and return) or a bug in the tenant-resolution path on the queried node, not a normal missing-tenant request (that yields 404).","commonSituations":"Hitting a node during a tenant offloading/deletion that is not yet reflected in its consistent view; multi-node clusters with replication lag or split state; bugs in RAFT-applied tenant state where the tenant record is logically absent but no error is propagated.","solutions":["Retry the GET against the same or another node — a transient race typically resolves and either returns the tenant or a proper 404.","Verify the tenant actually exists: GET /v1/schema/{class}/tenants and check the tenant name for exact case-sensitivity.","Confirm cluster health and RAFT replication status; if the nil response is reproducible and stable, it is a bug — capture class name, tenant name, consistency level and node, and report it to weaviate/weaviate.","If the tenant is genuinely gone (e.g. offloaded or deleted), re-create/activate it with POST /v1/schema/{class}/tenants before querying."],"exampleFix":"// client: handle the unexpected 422 by re-listing tenants and retrying\n// before\nresp, err := client.Schema().TenantsGetter().WithClassName(\"Article\").WithTenantName(\"tenant-1\").Do(ctx)\nif err != nil { return err } // assumes 404 is the only failure\n// after\nresp, err := client.Schema().TenantsGetter().WithClassName(\"Article\").Do(ctx)\nif err != nil { return err }\nfound := false\nfor _, t := range resp.Payload {\n  if t.Name == \"tenant-1\" { found = true; break }\n}\nif !found { return fmt.Errorf(\"tenant-1 does not exist; create or reactivate it first\") }\n// then retry the single-tenant GET","handlingStrategy":"validation","validationCode":"tenants, err := client.Schema().TenantsGetter().WithClassName(\"Article\").Do(ctx)\nif err != nil { return err }\nexists := slices.ContainsFunc(tenants.Payload, func(t *models.Tenant) bool { return t.Name == \"tenant-1\" && t.Status != models.TenantStatusOffloaded })\nif !exists { return fmt.Errorf(\"tenant-1 missing or offloaded\") }","typeGuard":"func tenantExists(tenants []*models.Tenant, name string) bool {\n  for _, t := range tenants {\n    if t != nil && t.Name == name { return true }\n  }\n  return false\n}","tryCatchPattern":"_, err := client.Schema().TenantGetter().WithClassName(\"Article\").WithTenantName(\"tenant-1\").Do(ctx)\nvar weaviateErr *fault.WeaviateClientError\nif errors.As(err, &weaviateErr) && weaviateErr.StatusCode == 422 {\n  // unexpected nil tenant: list tenants and retry once\n}","preventionTips":["Always list tenants (GET /schema/{class}/tenants) before fetching a single tenant in automated pipelines.","Check tenant status (HOT/COLD/OFFLOADED) — offloaded tenants will not resolve.","Treat a stable 422 'not found when it should have been' as a cluster-state bug; capture node + consistency level and report it.","Retry once with the same consistency level before giving up to rule out transient replication lag."],"tags":["weaviate","tenants","multi-tenancy","rest-api","invariant-violation"],"backgroundTag":"tenant-not-found","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"}