LykosAI/StabilityMatrix · error · ArgumentException

Relative URL is required

Error message

Relative URL is required

What it means

GetModelDetailsAsync validates its relativeUrl parameter before fetching the model's Next.js data page, throwing ArgumentException for null, empty, or whitespace URLs. The client needs a real route path (e.g. /models/12345) to locate the __NEXT_DATA__ payload.

Solutions

  1. Ensure the model's relative URL (e.g. "/models/{id}") is populated before calling
  2. Construct the URL from the model ID if only an ID is available: $"/models/{id}"
  3. Guard the call site against empty URLs before invoking

Example fix

// before
await api.GetModelDetailsAsync(model.PageUrl); // PageUrl may be ""
// after
if (string.IsNullOrWhiteSpace(model.PageUrl)) return null;
await api.GetModelDetailsAsync(model.PageUrl);
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrWhiteSpace(model.PageUrl)) { Logger.Warn("Model {Id} has no page URL", model.Id); return null; }

Type guard

bool HasRelativeUrl(string? url) => !string.IsNullOrWhiteSpace(url) && url.StartsWith('/');

Try / catch

try { return await api.GetModelDetailsAsync(url); }
catch (ArgumentException ex) { Logger.Warn(ex, "Missing relative URL"); return null; }

Prevention

When it happens

Trigger: Calling GetModelDetailsAsync with an empty string, null, or whitespace-only relativeUrl — typically when an upstream model URL field was never populated or was stripped during parsing.

Common situations: Model records imported from older data versions missing the page URL, a failed earlier parse yielding '', passing a raw ID instead of a URL without formatting.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of LykosAI/StabilityMatrix@af93d6ef57 (2026-09-12). Data as JSON: /api/errors/63a0893d060cb8aa. Report an issue: GitHub.

Appendix: source

Thrown at StabilityMatrix.Core/Api/CivArchiveApiClient.cs:166

            };

            cachedFilterOptions = new CacheEntry<CivArchiveFilterOptions>(DateTimeOffset.UtcNow, result);
            return result;
        }
        finally
        {
            filterOptionsLock.Release();
        }
    }

    public async Task<CivArchiveModelDetailsResponse> GetModelDetailsAsync(
        string relativeUrl,
        CancellationToken cancellationToken = default
    )
    {
        if (string.IsNullOrWhiteSpace(relativeUrl))
        {
            throw new ArgumentException("Relative URL is required", nameof(relativeUrl));
        }

        var nextDataPath = BuildDetailDataPath(relativeUrl);

        if (detailsCache.Get(nextDataPath) is { } cachedDetails && cachedDetails.IsFresh(DetailsCacheTtl))
        {
            return cachedDetails.Value;
        }

        var response = await GetNextDataAsync<CivArchiveDetailPageResponse>(nextDataPath, cancellationToken);

        var pageProps =
            response.PageProps
            ?? throw new InvalidOperationException("CivArchive detail page was missing pageProps");

        // A version-less /models/{id} data request returns a Next.js redirect payload pointing
        // at the model's primary version instead of pageProps.model — follow it like the
        // browser would. Guarded against self-redirects so a server quirk can't loop us.

View on GitHub (pinned to af93d6ef57)