Devolutions/UniGetUI · warning · InvalidOperationException

Exactly one of content or path must be supplied when importi

Error message

Exactly one of content or path must be supplied when importing a bundle.

What it means

ReadBundleContentAsync (called by ImportBundleAsync) requires exactly one source for the bundle data: either request.Content (inline string) or request.Path (file path). It computes hasContent and hasPath as non-whitespace checks and throws InvalidOperationException when both are true (ambiguous) or both are false (nothing to import). This is a mutually-exclusive input contract.

Source

Thrown at src/UniGetUI.Interface.IpcApi/IpcBundleApi.cs:483

            return (await imported.AsSerializableAsync()).Version;
        }

        if (package is InvalidImportedPackage invalid)
        {
            return invalid.AsSerializable_Incompatible().Version;
        }

        return package.VersionString;
    }

    private static async Task<string> ReadBundleContentAsync(IpcBundleImportRequest request)
    {
        bool hasContent = !string.IsNullOrWhiteSpace(request.Content);
        bool hasPath = !string.IsNullOrWhiteSpace(request.Path);

        if (hasContent == hasPath)
        {
            throw new InvalidOperationException(
                "Exactly one of content or path must be supplied when importing a bundle."
            );
        }

        if (hasContent)
        {
            return request.Content!;
        }

        return await File.ReadAllTextAsync(request.Path!);
    }

    private static BundleFormatType ResolveImportFormat(IpcBundleImportRequest request)
    {
        if (!string.IsNullOrWhiteSpace(request.Format))
        {
            return ParseFormat(request.Format);
        }

View on GitHub (pinned to 9b1d7d0eab)

Solutions

  1. Set exactly one of request.Content or request.Path; leave the other null.
  2. If importing from a file, set Path and leave Content null.
  3. If importing inline JSON/YAML/XML, set Content and leave Path null.
  4. Validate the XOR condition client-side before calling ImportBundleAsync.

Example fix

// before: both fields set (ambiguous)
await IpcBundleApi.ImportBundleAsync(new IpcBundleImportRequest { Content = json, Path = "/tmp/b.ubundle" });
// after: exactly one source
await IpcBundleApi.ImportBundleAsync(new IpcBundleImportRequest { Content = json });
// or
await IpcBundleApi.ImportBundleAsync(new IpcBundleImportRequest { Path = "/tmp/b.ubundle" });
Defensive patterns

Strategy: validation

Validate before calling

bool hasContent = !string.IsNullOrWhiteSpace(request.Content);
bool hasPath = !string.IsNullOrWhiteSpace(request.Path);
if (hasContent == hasPath)
    throw new ArgumentException("Provide exactly one of Content or Path.");

Type guard

static bool HasExactlyOneBundleSource(IpcBundleImportRequest r)
{
    bool c = !string.IsNullOrWhiteSpace(r.Content);
    bool p = !string.IsNullOrWhiteSpace(r.Path);
    return c ^ p;
}

Try / catch

try { await IpcBundleApi.ImportBundleAsync(request); }
catch (InvalidOperationException ex) when (ex.Message.Contains("content or path"))
{ /* client must set exactly one field */ }

Prevention

When it happens

Trigger: An IpcBundleImportRequest is passed to ImportBundleAsync where both Content and Path are set (ambiguous), or both are null/empty/whitespace (no data). The XOR condition hasContent == hasPath catches both cases: true==true (both set) and false==false (neither set).

Common situations: A client sends both an inline content blob and a file path, expecting the API to pick one. A client sends neither, expecting a file dialog or default. A UI form populates both fields. A serialization issue leaves both fields null when one should have been set.

Related errors


AI-assisted analysis of Devolutions/UniGetUI@9b1d7d0eab (2026-08-13). Data as JSON: /api/errors/05a3c920bd41e288. Report an issue: GitHub.