nopSolutions/nopCommerce · error · NopException

Exchange ratio not set for weight [{targetMeasureWeight.Name

Error message

Exchange ratio not set for weight [{targetMeasureWeight.Name}]

What it means

Thrown by MeasureService.ConvertFromPrimaryMeasureWeightAsync when converting a value FROM the base weight TO a target MeasureWeight whose Ratio is 0 (decimal.Zero). nopCommerce multiplies by Ratio, so a zero target ratio is treated as unconfigured and aborts with NopException instead of silently yielding zero for every conversion.

Source

Thrown at src/Libraries/Nop.Services/Directory/MeasureService.cs:349

    /// <param name="value">Value to convert</param>
    /// <param name="targetMeasureWeight">Target weight</param>
    /// <returns>
    /// A task that represents the asynchronous operation
    /// The task result contains the converted value
    /// </returns>
    public virtual async Task<decimal> ConvertFromPrimaryMeasureWeightAsync(decimal value,
        MeasureWeight targetMeasureWeight)
    {
        ArgumentNullException.ThrowIfNull(targetMeasureWeight);

        var result = value;
        var baseWeightIn = await GetMeasureWeightByIdAsync(_measureSettings.BaseWeightId);
        if (result == decimal.Zero || targetMeasureWeight.Id == baseWeightIn.Id)
            return result;

        var exchangeRatio = targetMeasureWeight.Ratio;
        if (exchangeRatio == decimal.Zero)
            throw new NopException($"Exchange ratio not set for weight [{targetMeasureWeight.Name}]");
        result *= exchangeRatio;

        return result;
    }

    /// <summary>
    /// Converts to primary measure weight
    /// </summary>
    /// <param name="value">Value to convert</param>
    /// <param name="sourceMeasureWeight">Source weight</param>
    /// <returns>
    /// A task that represents the asynchronous operation
    /// The task result contains the converted value
    /// </returns>
    public virtual async Task<decimal> ConvertToPrimaryMeasureWeightAsync(decimal value, MeasureWeight sourceMeasureWeight)
    {
        ArgumentNullException.ThrowIfNull(sourceMeasureWeight);

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. In Configuration > Measures > Weights, open the target weight unit named in the error and set a non-zero Ratio relative to the base weight.
  2. If the shipping plugin (UPS) triggers it, verify the plugin's selected MeasureWeight still exists and has a ratio after any DB restore or migration.
  3. Guard the caller: skip conversion (or use the base value) when targetMeasureWeight.Ratio == decimal.Zero.
  4. Ensure BaseWeightId in measure settings still points to an existing, configured weight.

Example fix

// before
weight = await _measureService.ConvertFromPrimaryMeasureWeightAsync(weight, _measureWeight);

// after — guard the target weight ratio before the call
if (weight != decimal.Zero && _measureWeight.Id != baseWeightId && _measureWeight.Ratio == decimal.Zero)
    throw new InvalidOperationException($"Weight '{_measureWeight.Name}' has no ratio; configure it in Configuration > Measures.");
weight = await _measureService.ConvertFromPrimaryMeasureWeightAsync(weight, _measureWeight);
Defensive patterns

Strategy: validation

Validate before calling

// Validate before converting from the base weight to a target weight
var baseWt = await _measureService.GetMeasureWeightByIdAsync(_measureSettings.BaseWeightId);
if (value != decimal.Zero && targetMeasureWeight.Id != baseWt.Id && targetMeasureWeight.Ratio == decimal.Zero)
    throw new InvalidOperationException($"Configure a non-zero Ratio for weight '{targetMeasureWeight.Name}'.");
var converted = await _measureService.ConvertFromPrimaryMeasureWeightAsync(value, targetMeasureWeight);

Type guard

static bool IsTargetWeightConvertible(MeasureWeight target, MeasureWeight baseWt, decimal value)
    => value == decimal.Zero || target.Id == baseWt.Id || target.Ratio != decimal.Zero;

Try / catch

try { weight = await _measureService.ConvertFromPrimaryMeasureWeightAsync(weight, targetWt); }
catch (NopException ex) when (ex.Message.StartsWith("Exchange ratio not set for weight"))
{ /* report 'configure the target weight ratio'; do not silently return value */ }

Prevention

When it happens

Trigger: Calling ConvertFromPrimaryMeasureWeightAsync(value, targetMeasureWeight) where targetMeasureWeight.Ratio == 0m, targetMeasureWeight.Id != BaseWeightId, and value != 0m. Hit indirectly through ConvertMeasureWeightAsync or directly by plugins (e.g. UPS shipping at UPSService.cs:774, Omnisend at OmnisendEventsService.cs:392).

Common situations: A shipping plugin (UPS) converts package weight into its configured MeasureWeight but that weight's Ratio is 0; a newly added weight unit lacks a ratio; the base weight was changed but other weight units were not re-normalized; sample data installed without weight ratios.

Related errors


AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13). Data as JSON: /api/errors/b9b81e311d7ca2fe. Report an issue: GitHub.