{"record":{"id":"59b44c5c0f516f3f","repo":"microsoft/aspire","slug":"terminalannotation-has-already-been-initialized","errorCode":null,"errorMessage":"TerminalAnnotation has already been initialized.","messagePattern":"TerminalAnnotation has already been initialized\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting/ApplicationModel/TerminalAnnotation.cs","lineNumber":70,"sourceCode":"    /// Gets a value indicating whether <see cref=\"Initialize\"/> has been called yet.\n    /// Production code initializes during <see cref=\"BeforeStartEvent\"/>; tests that\n    /// inspect <see cref=\"TerminalHosts\"/> need to publish that event manually first.\n    /// </summary>\n    public bool IsInitialized { get; private set; }\n\n    /// <summary>\n    /// Populates <see cref=\"TerminalHosts\"/> exactly once. Called by the\n    /// <see cref=\"BeforeStartEvent\"/> subscriber installed by\n    /// <see cref=\"TerminalResourceBuilderExtensions.WithTerminal{T}(IResourceBuilder{T}, Action{TerminalOptions}?)\"/>.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown when called more than once.</exception>\n    internal void Initialize(IReadOnlyList<TerminalHostResource> terminalHosts)\n    {\n        ArgumentNullException.ThrowIfNull(terminalHosts);\n\n        if (IsInitialized)\n        {\n            throw new InvalidOperationException(\"TerminalAnnotation has already been initialized.\");\n        }\n\n        if (terminalHosts.Count == 0)\n        {\n            throw new ArgumentException(\"At least one terminal host is required.\", nameof(terminalHosts));\n        }\n\n        for (var i = 0; i < terminalHosts.Count; i++)\n        {\n            if (terminalHosts[i] is null)\n            {\n                throw new ArgumentException($\"Terminal host at index {i} is null.\", nameof(terminalHosts));\n            }\n        }\n\n        _terminalHosts = terminalHosts;\n        IsInitialized = true;\n    }","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/ApplicationModel/TerminalAnnotation.cs#L52-L88","documentation":"TerminalAnnotation is a singleton-style application-model annotation that can only be initialized once with its set of TerminalHostResources. Initialize throws InvalidOperationException if IsInitialized is already true, because re-initializing would replace an already-materialized terminal host set. The listed callers (MaterializeTerminalHostsAsync, AddSyntheticTerminalAnnotation, BuildModel, CreateHarness) are the internal paths that initialize it during app model construction/publish.","triggerScenarios":"Calling TerminalAnnotation.Initialize twice on the same annotation instance — e.g. a custom publish step or harness that invokes initialization after the framework (BuildModel/CreateHarness) already did, or materializing terminal hosts in both publish and run paths on a shared model.","commonSituations":"Custom dashboard/terminal tooling that builds the model more than once; tests creating a harness then manually initializing; re-running a distributed application builder's publish pipeline on the same ApplicationModel instance.","solutions":["Check TerminalAnnotation.IsInitialized before calling Initialize and skip if already true.","Ensure only one pipeline stage initializes the annotation (let the framework's BuildModel/CreateHarness do it).","Build a fresh ApplicationModel (re-run the distributed application builder) instead of reusing an already-initialized model.","Catch InvalidOperationException if double-init is an expected benign race in custom tooling."],"exampleFix":"// before\nterminalAnnotation.Initialize(terminalHosts);\n\n// after\nif (!terminalAnnotation.IsInitialized)\n{\n    terminalAnnotation.Initialize(terminalHosts);\n}","handlingStrategy":"validation","validationCode":"if (terminalAnnotation.IsInitialized)\n    return; // skip redundant initialization","typeGuard":null,"tryCatchPattern":"try\n{\n    terminalAnnotation.Initialize(terminalHosts);\n}\ncatch (InvalidOperationException ex) when (terminalAnnotation.IsInitialized)\n{\n    // Already initialized by another pipeline stage; safe to ignore.\n}","preventionTips":["Initialize TerminalAnnotation exactly once, ideally in the framework's model-build path.","Check IsInitialized before any manual Initialize call in custom tooling or tests.","Build a fresh ApplicationModel per pipeline run instead of reusing an initialized model."],"tags":["invalid-state","initialization","app-model"],"backgroundTag":"invalid-state-transition","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"}