{"record":{"id":"9991c3e1ea8eeaa3","repo":"microsoft/aspire","slug":"failed-to-register-cancellation-token-with-id-id","errorCode":null,"errorMessage":"Failed to register cancellation token with ID '{id}'","messagePattern":"Failed to register cancellation token with ID '(.+?)'","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.RemoteHost/CancellationTokenRegistry.cs","lineNumber":35,"sourceCode":"    private int _counter;\n    private bool _disposed;\n\n    /// <summary>\n    /// Creates a new CancellationTokenSource and returns its ID and token.\n    /// The ID can be passed to the guest, which can use it to cancel the token.\n    /// </summary>\n    /// <returns>A tuple of (tokenId, cancellationToken).</returns>\n    public (string TokenId, CancellationToken Token) Create()\n    {\n        ObjectDisposedException.ThrowIf(_disposed, this);\n\n        var id = $\"ct_{Interlocked.Increment(ref _counter)}\";\n        var cts = new CancellationTokenSource();\n\n        if (!_sources.TryAdd(id, cts))\n        {\n            cts.Dispose();\n            throw new InvalidOperationException($\"Failed to register cancellation token with ID '{id}'\");\n        }\n\n        return (id, cts.Token);\n    }\n\n    /// <summary>\n    /// Creates a new CancellationTokenSource linked to an existing token.\n    /// This is useful when you need to combine multiple cancellation sources.\n    /// </summary>\n    /// <param name=\"linkedToken\">The token to link to.</param>\n    /// <returns>A tuple of (tokenId, cancellationToken).</returns>\n    public (string TokenId, CancellationToken Token) CreateLinked(CancellationToken linkedToken)\n    {\n        ObjectDisposedException.ThrowIf(_disposed, this);\n\n        var id = $\"ct_{Interlocked.Increment(ref _counter)}\";\n        var cts = CancellationTokenSource.CreateLinkedTokenSource(linkedToken);\n","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.RemoteHost/CancellationTokenRegistry.cs#L17-L53","documentation":"CancellationTokenRegistry.Create generates an id (ct_N) and a fresh CancellationTokenSource, then atomically inserts them into a ConcurrentDictionary. If TryAdd fails — meaning a token with that same id is somehow already registered — it disposes the CTS and throws this InvalidOperationException. Under normal operation the incrementing counter makes collisions impossible, so this is a defensive invariant check against registry corruption or reuse.","triggerScenarios":"Calling CancellationTokenRegistry.Create when _sources already contains the generated ct_N id — only possible if the counter and dictionary got out of sync (e.g. a custom subclass reseeded the counter, or entries were manually injected).","commonSituations":"Practically never hit in production; seen when tests or tools manipulate registry internals, or when a patched/replaced registry implementation breaks the monotonic-counter assumption.","solutions":["Do not manipulate the registry's counter or dictionary from outside; create tokens only via Create/CreateLinked.","Replace the registry instance (or recreate it) if its internal state has been corrupted.","Verify no custom code adds 'ct_*' keys directly into the underlying ConcurrentDictionary.","If seen after patching assemblies, restore the stock CancellationTokenRegistry implementation."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { var (id, token) = registry.Create(); }\ncatch (InvalidOperationException ex) when (ex.Message.StartsWith(\"Failed to register cancellation token\"))\n{ log.LogError(ex, \"Cancellation registry state corrupted; recreating registry\"); registry = new CancellationTokenRegistry(); throw; }","preventionTips":["Create tokens only through the registry's public Create/CreateLinked APIs.","Never inject or mutate ct_* entries in the underlying dictionary.","Treat repeated occurrences as a symptom of patched/corrupted registry state."],"tags":["cancellation","registry","concurrency","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}