nopSolutions/nopCommerce · error · NopException

Exchange ratio not set for weight [{sourceMeasureWeight.Name

Error message

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

What it means

Thrown by MeasureService.ConvertToPrimaryMeasureWeightAsync when converting a value TO the base weight FROM a source MeasureWeight whose Ratio is 0 (decimal.Zero). nopCommerce divides by Ratio, so a zero source ratio would produce a wrong result; it aborts with NopException instead.

Source

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

    /// </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);

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

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

        return result;
    }

    #endregion

    #endregion
}

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. In Configuration > Measures > Weights, set a non-zero Ratio on the source weight unit named in the error.
  2. Verify BaseWeightId points to an existing configured weight so the source-vs-base comparison at line 369 is meaningful.
  3. Guard the caller: only invoke conversion when sourceMeasureWeight.Ratio != decimal.Zero.
  4. If migrating data, run a one-time script asserting every published MeasureWeight has Ratio != 0 before enabling the store.

Example fix

// before
var baseWeight = await _measureService.ConvertToPrimaryMeasureWeightAsync(productWeight, sourceWeight);

// after — validate the source ratio first
if (productWeight != decimal.Zero && sourceWeight.Id != baseWeightId && sourceWeight.Ratio == decimal.Zero)
    throw new InvalidOperationException($"Source weight '{sourceWeight.Name}' has no ratio.");
var baseWeight = await _measureService.ConvertToPrimaryMeasureWeightAsync(productWeight, sourceWeight);
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Try / catch

try { result = await _measureService.ConvertToPrimaryMeasureWeightAsync(value, srcWt); }
catch (NopException ex) when (ex.Message.StartsWith("Exchange ratio not set for weight"))
{ /* surface 'configure the source weight ratio'; never substitute zero */ }

Prevention

When it happens

Trigger: Calling ConvertToPrimaryMeasureWeightAsync(value, sourceMeasureWeight) where sourceMeasureWeight.Ratio == 0m, sourceMeasureWeight.Id != BaseWeightId, and value != 0m. Reached via ConvertMeasureWeightAsync (the public weight-conversion entry point at line 318) or directly.

Common situations: Product weight stored in a unit whose MeasureWeight row has Ratio 0 (newly added unit, sample-data gap, or migration that cleared ratios); admin changed the base weight unit without re-keying all other units; custom import created weight records without ratios.

Related errors


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