{"record":{"id":"a678ddee0ce6eaec","repo":"microsoft/aspire","slug":"interaction-interactionid-is-not-accepting-file-uploads","errorCode":null,"errorMessage":"Interaction '{interactionId}' is not accepting file uploads.","messagePattern":"Interaction '(.+?)' is not accepting file uploads\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting/Dashboard/InteractionFileUploadStore.cs","lineNumber":47,"sourceCode":"    /// <summary>\n    /// Registers an interaction and the file inputs that can own uploaded files.\n    /// </summary>\n    public void StartInteraction(int interactionId, IReadOnlyList<(string InputName, int MaxFileCount)> fileInputs)\n    {\n        if (_interactions.TryAdd(interactionId, new FileInteraction(fileInputs)))\n        {\n            _logger.LogDebug(\"Started tracking file uploads for interaction {InteractionId}.\", interactionId);\n        }\n    }\n\n    /// <summary>\n    /// Creates a new temp file path and returns the file ID and path.\n    /// </summary>\n    public (string FileId, string FilePath) CreateEntry(string originalFileName, int interactionId, string inputName)\n    {\n        if (!_interactions.TryGetValue(interactionId, out var interaction))\n        {\n            throw new InvalidOperationException($\"Interaction '{interactionId}' is not accepting file uploads.\");\n        }\n\n        lock (interaction)\n        {\n            if (interaction.State != FileInteractionState.InProgress)\n            {\n                throw new InvalidOperationException($\"Interaction '{interactionId}' is not accepting file uploads.\");\n            }\n\n            if (!interaction.FileInputLimits.TryGetValue(inputName, out var maxFileCount))\n            {\n                throw new InvalidOperationException($\"Interaction '{interactionId}' is not accepting file uploads for input '{inputName}'.\");\n            }\n\n            // Each client submits one file selection per input during an interaction. Multi-file selections upload\n            // their files sequentially as part of that single selection, so every upload counts toward this limit.\n            // Count uploads in progress as reserved slots so concurrent requests cannot exceed the input's limit.\n            var fileCount = interaction.Files.Values.Count(entry => string.Equals(entry.InputName, inputName, StringComparisons.InteractionInputName));","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/Dashboard/InteractionFileUploadStore.cs#L29-L65","documentation":"InteractionFileUploadStore.CreateEntry registers a temp file for a file upload tied to a dashboard interaction. If the interaction id is not present in the store (no active interaction accepting uploads), an InvalidOperationException is thrown. Uploads are only valid while their interaction exists and is in progress.","triggerScenarios":"Calling CreateEntry (via the UploadFile RPC) with an interactionId that was never registered, or whose interaction has already completed/failed and been removed from the store.","commonSituations":"User closes or submits the interaction while an upload is still streaming; a stale dashboard session retries an upload after the interaction ended; a custom client invents an interaction id.","solutions":["Ensure the interaction is still open (InProgress) before uploading; if it completed, restart the interaction and upload again.","Use the exact interactionId returned by the interaction API — do not fabricate ids.","Handle the failure client-side: abort the upload and re-create the interaction/file selection.","Check timing in automation: wait for the interaction to be active before starting the upload stream."],"exampleFix":"// before\nvar (fileId, path) = store.CreateEntry(name, staleInteractionId, input); // throws if the interaction is gone\n// after\nif (!store.TryGetInteraction(staleInteractionId, out var interaction) || interaction.State != FileInteractionState.InProgress)\n{\n    interactionId = await promptForNewInteractionAsync(); // recreate the interaction, then upload\n}\nvar (fileId, path) = store.CreateEntry(name, interactionId, input);","handlingStrategy":"try-catch","validationCode":"// Before uploading, confirm the interaction is still active via the interaction API and keep the returned interactionId.","typeGuard":null,"tryCatchPattern":"try { await uploadTask; } catch (InvalidOperationException ex) when (ex.Message.Contains(\"not accepting file uploads\")) { logger.LogWarning(\"Interaction {Id} closed during upload; restarting interaction and retrying.\", interactionId); interactionId = await recreateInteractionAsync(); }","preventionTips":["Upload only while the interaction is InProgress","Use the exact interactionId from the interaction API","Handle user-closed interactions by aborting uploads promptly","In automation, wait for the interaction to be active before streaming"],"tags":["interaction","upload","state","dashboard"],"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-21T09:17:21.228Z"}