elsa-workflows/elsa-core · error · InvalidOperationException
Elsa Platform endpoint is required.
Error message
Elsa Platform endpoint is required.
What it means
BuildUri resolves request paths against _options.PlatformEndpoint. If PlatformEndpoint is null, it throws this InvalidOperationException because no request can be addressed. Absolute paths like artifact DownloadUrls bypass the endpoint, but the endpoint itself is always mandatory.
Solutions
- Set PlatformEndpoint to the absolute Platform base URL, e.g. https://platform.example.com.
- Ensure options binding/validation runs at startup so this surfaces as a clear config error instead of a runtime failure.
- Fix the missing configuration key in appsettings/environment variables for the deployment.
Example fix
// before
var client = new PlatformRuntimeCommandClient(httpClient, new ElsaPlatformIntegrationOptions { EngineId = id });
// after
var options = new ElsaPlatformIntegrationOptions { PlatformEndpoint = new Uri("https://platform.example.com"), EngineId = id, WorkspaceId = wsId };
options.Validate();
var client = new PlatformRuntimeCommandClient(httpClient, options); Defensive patterns
Strategy: validation
Validate before calling
if (options.Enabled && string.IsNullOrWhiteSpace(options.PlatformEndpoint?.ToString()))
throw new InvalidOperationException("PlatformEndpoint must be configured before using the command client."); Type guard
bool HasEndpoint(ElsaPlatformIntegrationOptions o) => !string.IsNullOrWhiteSpace(o.PlatformEndpoint?.AbsoluteUri);
Try / catch
try { var commands = await client.PollAsync(ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("endpoint is required"))
{
logger.LogError(ex, "PlatformEndpoint is not configured.");
} Prevention
- Always construct the client through Elsa's feature registration so options validation runs.
- Set PlatformEndpoint via configuration and call ValidateOnStart.
- Add an integration smoke test that performs a poll against configured options.
When it happens
Trigger: Any PlatformRuntimeCommandClient call (PollAsync, complete/report, DownloadArtifactAsync) when _options.PlatformEndpoint was never assigned — typically because Validate() was never run or options were constructed in code without the endpoint.
Common situations: Registering the client manually without going through the feature's options pipeline that validates the endpoint; configuration key Elsa:PlatformIntegration:PlatformEndpoint missing in the environment; tests newing up options with only EngineId set.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Elsa Platform claim lease duration must be between 1 second…
- Elsa Platform endpoint is required when Platform…
- Elsa Platform engine ID is required when Platform…
- Elsa Platform engine secret is required when Platform…
- Elsa Platform maximum artifact size must be between 1 byte…
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/063ea93afb37350b.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Platform.Integration/Services/PlatformRuntimeCommandClient.cs:115
private HttpRequestMessage CreateRequest(HttpMethod method, Uri uri)
{
var request = new HttpRequestMessage(method, uri);
if (!string.IsNullOrWhiteSpace(_options.EngineSecret))
request.Headers.TryAddWithoutValidation(EngineSecretHeaderName, _options.EngineSecret);
return request;
}
private async Task<HttpResponseMessage> SendJsonAsync<TRequest>(Uri uri, TRequest body, CancellationToken cancellationToken)
{
var request = CreateRequest(HttpMethod.Post, uri);
request.Content = JsonContent.Create(body, options: JsonOptions);
return await httpClient.SendAsync(request, cancellationToken);
}
private Uri BuildUri(string path)
{
var endpoint = _options.PlatformEndpoint ?? throw new InvalidOperationException("Elsa Platform endpoint is required.");
if (Uri.TryCreate(path, UriKind.Absolute, out var absoluteUri))
return absoluteUri;
var relative = path.StartsWith("/api/", StringComparison.OrdinalIgnoreCase)
? path
: $"/api/workspaces/{_options.WorkspaceId:D}{path}";
return new Uri($"{endpoint.AbsoluteUri.TrimEnd('/')}{relative}");
}
private async Task CopyBoundedAsync(Stream source, Stream destination, CancellationToken cancellationToken)
{
var buffer = new byte[81920];
long total = 0;
while (true)
{
var read = await source.ReadAsync(buffer, cancellationToken);
if (read == 0)
return;View on GitHub (pinned to fe9217bdfa)