{"record":{"id":"9a49a1cc3c5c5e5f","repo":"elsa-workflows/elsa-core","slug":"platform-runtime-command-artifact-does-not-include-a","errorCode":null,"errorMessage":"Platform runtime command artifact does not include a download URL.","messagePattern":"Platform runtime command artifact does not include a download URL\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Platform.Integration/Services/PlatformRuntimeCommandClient.cs","lineNumber":52,"sourceCode":"            BuildUri($\"/deployments/runtime/commands/{commandId:D}/claim\"),\n            new PlatformRuntimeCommandClaimRequest(_options.EngineId, _options.WorkerId, (int)_options.ClaimLeaseDuration.TotalSeconds),\n            cancellationToken);\n\n        if (response.StatusCode == HttpStatusCode.Conflict || response.StatusCode == HttpStatusCode.NotFound)\n            return null;\n\n        response.EnsureSuccessStatusCode();\n        return await response.Content.ReadFromJsonAsync<PlatformRuntimeCommandClaimResponse>(JsonOptions, cancellationToken);\n    }\n\n    public async Task<Stream> DownloadArtifactAsync(\n        PlatformRuntimeCommand command,\n        PlatformArtifactItem artifact,\n        string leaseToken,\n        CancellationToken cancellationToken = default)\n    {\n        if (string.IsNullOrWhiteSpace(artifact.DownloadUrl))\n            throw new InvalidOperationException(\"Platform runtime command artifact does not include a download URL.\");\n\n        using var request = CreateRequest(HttpMethod.Get, BuildUri(artifact.DownloadUrl));\n        request.Headers.Add(LeaseHeaderName, leaseToken);\n        request.Headers.Add(WorkerHeaderName, _options.WorkerId);\n        using var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);\n        response.EnsureSuccessStatusCode();\n        var stream = await response.Content.ReadAsStreamAsync(cancellationToken);\n        var buffer = new MemoryStream();\n        await CopyBoundedAsync(stream, buffer, cancellationToken);\n        buffer.Position = 0;\n        return buffer;\n    }\n\n    public Task ReportProgressAsync(\n        Guid commandId,\n        string leaseToken,\n        string status,\n        int? percentComplete,","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Platform.Integration/Services/PlatformRuntimeCommandClient.cs#L34-L70","documentation":"DownloadArtifactAsync downloads the payload of a Platform runtime command artifact. The Platform must supply a DownloadUrl on each artifact; when it is missing or blank, the client refuses to build a request and throws this InvalidOperationException.","triggerScenarios":"Polling returns a command whose artifact has DownloadUrl null/empty/whitespace, then DownloadArtifactAsync is called for that artifact.","commonSituations":"Platform API version mismatch returning an older artifact shape without download URLs; the artifact upload on the Platform side failed or expired, so the URL was omitted; deserialization silently left the property null due to JSON casing settings.","solutions":["Inspect the raw command response to confirm whether the Platform actually omitted DownloadUrl; upgrade/align the Platform service if it is an API version mismatch.","Re-trigger the command on the Platform so the artifact (and its URL) is regenerated.","Add a guard before calling DownloadArtifactAsync: skip or surface an actionable error when DownloadUrl is null."],"exampleFix":"// before\nvar bytes = await client.DownloadArtifactAsync(command, artifact, leaseToken);\n// after\nif (string.IsNullOrWhiteSpace(artifact.DownloadUrl))\n    throw new InvalidOperationException($\"Artifact {artifact.Name} has no download URL; re-issue the command.\");\nvar bytes = await client.DownloadArtifactAsync(command, artifact, leaseToken);","handlingStrategy":"type-guard","validationCode":"if (string.IsNullOrWhiteSpace(artifact.DownloadUrl))\n    throw new InvalidOperationException($\"Artifact '{artifact.Name}' lacks a download URL; re-issue the command.\");","typeGuard":"bool IsDownloadable(PlatformArtifactItem a) => !string.IsNullOrWhiteSpace(a.DownloadUrl);","tryCatchPattern":"try { var bytes = await client.DownloadArtifactAsync(command, artifact, leaseToken, ct); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"download URL\"))\n{\n    logger.LogWarning(ex, \"Artifact for command {CommandId} has no download URL.\", command.Id);\n}","preventionTips":["Keep the runtime and Platform API versions aligned so artifact payloads always include URLs.","Log the raw command JSON when artifacts look malformed to diagnose server-side issues.","Handle missing URLs gracefully by re-requesting the command from the Platform."],"tags":["http","api-client","artifact","platform-integration"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}