{"record":{"id":"3689bab0e126d8f1","repo":"dotnet/orleans","slug":"index-indexname-in-table-tablename-has-failed","errorCode":null,"errorMessage":"Index {indexName} in table {tableName} has failed to reach the desired status of {desiredStatus}","messagePattern":"Index (.+?) in table (.+?) has failed to reach the desired status of (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/AWS/Shared/Storage/DynamoDBStorage.cs","lineNumber":452,"sourceCode":"        private async Task<TableDescription> TableIndexWaitOnStatusAsync(string tableName, string indexName, IndexStatus whileStatus, IndexStatus? desiredStatus = null, int delay = 2000, CancellationToken cancellationToken = default)\n        {\n            TableDescription ret;\n            GlobalSecondaryIndexDescription? index = null;\n\n            do\n            {\n                if (index != null)\n                {\n                    await Task.Delay(delay, cancellationToken);\n                }\n\n                ret = (await GetTableDescription(tableName, cancellationToken))!;\n                index = ret.GlobalSecondaryIndexes?.Find(index => index.IndexName == indexName);\n            } while (index != null && index.IndexStatus == whileStatus);\n\n            if (desiredStatus != null && (index == null || index.IndexStatus != desiredStatus))\n            {\n                throw new InvalidOperationException($\"Index {indexName} in table {tableName} has failed to reach the desired status of {desiredStatus}\");\n            }\n\n            return ret;\n        }\n\n        /// <summary>\n        /// Delete a table from DynamoDB\n        /// </summary>\n        /// <param name=\"tableName\">The name of the table to delete</param>\n        /// <returns></returns>\n        public Task DeleTableAsync(string tableName)\n        {\n            try\n            {\n                return _ddbClient.DeleteTableAsync(new DeleteTableRequest { TableName = tableName });\n            }\n            catch (Exception exc)\n            {","sourceCodeStart":434,"sourceCodeEnd":470,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/AWS/Shared/Storage/DynamoDBStorage.cs#L434-L470","documentation":"Thrown by TableIndexWaitOnStatusAsync after polling a Global Secondary Index when desiredStatus was requested but the index either could not be found or ended in a status other than desired (typically ACTIVE). The loop waits while the GSI is in whileStatus, then asserts the final IndexStatus equals desiredStatus; a FAILED or missing index trips the guard.","triggerScenarios":"Produced during provider init when initializing a table that defines a GSI and waiting for it to become ACTIVE. Triggered by the GSI creation failing (e.g., not enough capacity for backfilling), the index being deleted out-of-band, or DescribeTable no longer reporting the index.","commonSituations":"A GSI backfill running out of provisioned capacity and failing; an operator dropping the index mid-deploy; misconfiguration of secondary indexes between deployments; eventual-consistency returning a transiently missing index.","solutions":["Run DescribeTable and inspect GlobalSecondaryIndexes for the failing index name and its IndexStatus.","Fix capacity/quota issues (raise write capacity on the table during backfill, or switch to PAY_PER_REQUEST) and redeploy so Init re-attempts.","If the index was removed intentionally, update the provider's secondary-index configuration so it no longer expects it.","For transient cases, confirm the index is ACTIVE in the AWS console and retry silo startup."],"exampleFix":"// before: GSI backfill fails under low provisioned write capacity\nopt.UseProvisionedThroughput = true;\nopt.WriteCapacityUnits = 5; // too low for GSI backfill\n\n// after: allow enough capacity for backfill (or on-demand)\nopt.UseProvisionedThroughput = false; // PAY_PER_REQUEST during deployment\n// then revert to provisioned once the GSI is ACTIVE if desired","handlingStrategy":"retry","validationCode":"// Pre-flight: confirm GSIs exist and are ACTIVE before relying on them\nvar desc = await DescribeExistingTableAsync(tableName);\nvar gsi = desc?.GlobalSecondaryIndexes?.Find(i => i.IndexName == expectedIndex);\nif (gsi is null || gsi.IndexStatus != IndexStatus.ACTIVE)\n    _logger.LogWarning(\"GSI {Index} is {Status}; init may fail\", expectedIndex, gsi?.IndexStatus);","typeGuard":"static bool IsIndexActive(GlobalSecondaryIndexDescription? i) =>\n    i is not null && i.IndexStatus == IndexStatus.ACTIVE;","tryCatchPattern":"try { await silo.StartAsync(); }\ncatch (InvalidOperationException ix) when (ix.Message.Contains(\"has failed to reach the desired status\"))\n{\n    _logger.LogCritical(\"DynamoDB GSI did not reach ACTIVE; raise capacity or remove the index expectation and retry\");\n    throw;\n}","preventionTips":["Provide enough write capacity (or on-demand) for GSI backfilling during schema updates.","Do not drop GSIs out-of-band during deployment.","Keep secondary-index configuration consistent across deployments.","Confirm GSIs are ACTIVE in the console before retrying startup after a failure."],"tags":["dynamodb","gsi","index-status","provisioning"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}