PrismLibrary/Prism · error · ArgumentNullException

candidateNavigationContract

Error message

candidateNavigationContract

What it means

RegionNavigationContentLoader.GetCandidatesFromRegion throws ArgumentNullException when candidateNavigationContract is null or empty (the 'region' parameter is additionally guarded by ArgumentNullException.ThrowIfNull). It needs the contract name to match candidate views already present in the region.

Solutions

  1. Pass a non-empty view/contract name to the navigation API
  2. Validate/trim the navigation string before RequestNavigation
  3. Fix the source of the empty contract (binding, route parsing)
  4. When writing a custom content loader, guard the contract parameter yourself

Example fix

// before
regionManager.RequestNavigate(new Uri(string.Empty, UriKind.Relative));
// after
if (string.IsNullOrWhiteSpace(targetName)) return;
regionManager.RequestNavigate(targetName);
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrWhiteSpace(contract)) return Enumerable.Empty<VisualElement>();
var candidates = loader.GetCandidatesFromRegion(region, contract);

Type guard

bool HasContract(string? c) => !string.IsNullOrWhiteSpace(c);

Try / catch

try { var cands = loader.GetCandidatesFromRegion(region, contract); }
catch (ArgumentNullException ex) { logger.Warn(ex, "Empty navigation contract"); }

Prevention

When it happens

Trigger: Calling GetCandidatesFromRegion with an empty string or null contract — e.g. regionManager.RequestNavigation with an empty name, or a custom content loader invoked with an unpopulated navigation URI segment.

Common situations: Navigation target name built dynamically from bindings that evaluated to empty; custom IRegionNavigationContentLoader implementations passing through unparsed URIs; RequestNavigation called before the navigation path was computed.

Related errors


AI-assisted analysis of PrismLibrary/Prism@358118cd64 (2026-09-15). Data as JSON: /api/errors/b786e24ced07cb77. Report an issue: GitHub.

Appendix: source

Thrown at src/Maui/Prism.Maui/Navigation/Regions/Navigation/RegionNavigationContentLoader.cs:109

        var candidateTargetContract = UriParsingHelper.EnsureAbsolute(navigationContext.Uri).AbsolutePath;
        candidateTargetContract = candidateTargetContract.TrimStart('/');
        return Uri.UnescapeDataString(candidateTargetContract);
    }

    /// <summary>
    /// Returns the set of candidates that may satisfy this navigation request.
    /// </summary>
    /// <param name="region">The region containing items that may satisfy the navigation request.</param>
    /// <param name="candidateNavigationContract">The candidate navigation target as determined by <see cref="GetContractFromNavigationContext"/></param>
    /// <returns>An enumerable of candidate objects from the <see cref="IRegion"/></returns>
    protected virtual IEnumerable<VisualElement> GetCandidatesFromRegion(IRegion region, string candidateNavigationContract)
    {
        ArgumentNullException.ThrowIfNull(region);

        if (string.IsNullOrEmpty(candidateNavigationContract))
        {
            throw new ArgumentNullException(nameof(candidateNavigationContract));
        }

        var contractCandidates = RegionNavigationContentLoader.GetCandidatesFromRegionViews(region, candidateNavigationContract);

        if (!contractCandidates.Any())
        {
            var registry = region.Container().Resolve<IRegionNavigationRegistry>();
            var registration = registry.Registrations.FirstOrDefault(x => x.Type == ViewType.Region && (x.Name == candidateNavigationContract || x.View.Name == candidateNavigationContract || x.View.FullName == candidateNavigationContract));
            if (registration is not null)
            {
                RegionNavigationContentLoader.GetCandidatesFromRegionViews(region, registration.View.FullName);
            }

            return [];
        }

        return contractCandidates;
    }

View on GitHub (pinned to 358118cd64)