{"record":{"id":"b9b81e311d7ca2fe","repo":"nopSolutions/nopCommerce","slug":"exchange-ratio-not-set-for-weight-targetmeasurew","errorCode":null,"errorMessage":"Exchange ratio not set for weight [{targetMeasureWeight.Name}]","messagePattern":"Exchange ratio not set for weight \\[(.+?)\\]","errorType":"exception","errorClass":"NopException","httpStatus":null,"severity":"error","filePath":"src/Libraries/Nop.Services/Directory/MeasureService.cs","lineNumber":349,"sourceCode":"    /// <param name=\"value\">Value to convert</param>\r\n    /// <param name=\"targetMeasureWeight\">Target weight</param>\r\n    /// <returns>\r\n    /// A task that represents the asynchronous operation\r\n    /// The task result contains the converted value\r\n    /// </returns>\r\n    public virtual async Task<decimal> ConvertFromPrimaryMeasureWeightAsync(decimal value,\r\n        MeasureWeight targetMeasureWeight)\r\n    {\r\n        ArgumentNullException.ThrowIfNull(targetMeasureWeight);\r\n\r\n        var result = value;\r\n        var baseWeightIn = await GetMeasureWeightByIdAsync(_measureSettings.BaseWeightId);\r\n        if (result == decimal.Zero || targetMeasureWeight.Id == baseWeightIn.Id)\r\n            return result;\r\n\r\n        var exchangeRatio = targetMeasureWeight.Ratio;\r\n        if (exchangeRatio == decimal.Zero)\r\n            throw new NopException($\"Exchange ratio not set for weight [{targetMeasureWeight.Name}]\");\r\n        result *= exchangeRatio;\r\n\r\n        return result;\r\n    }\r\n\r\n    /// <summary>\r\n    /// Converts to primary measure weight\r\n    /// </summary>\r\n    /// <param name=\"value\">Value to convert</param>\r\n    /// <param name=\"sourceMeasureWeight\">Source weight</param>\r\n    /// <returns>\r\n    /// A task that represents the asynchronous operation\r\n    /// The task result contains the converted value\r\n    /// </returns>\r\n    public virtual async Task<decimal> ConvertToPrimaryMeasureWeightAsync(decimal value, MeasureWeight sourceMeasureWeight)\r\n    {\r\n        ArgumentNullException.ThrowIfNull(sourceMeasureWeight);\r\n\r","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/nopSolutions/nopCommerce/blob/64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2/src/Libraries/Nop.Services/Directory/MeasureService.cs#L331-L367","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["In Configuration > Measures > Weights, open the target weight unit named in the error and set a non-zero Ratio relative to the base weight.","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.","Guard the caller: skip conversion (or use the base value) when targetMeasureWeight.Ratio == decimal.Zero.","Ensure BaseWeightId in measure settings still points to an existing, configured weight."],"exampleFix":"// before\nweight = await _measureService.ConvertFromPrimaryMeasureWeightAsync(weight, _measureWeight);\n\n// after — guard the target weight ratio before the call\nif (weight != decimal.Zero && _measureWeight.Id != baseWeightId && _measureWeight.Ratio == decimal.Zero)\n    throw new InvalidOperationException($\"Weight '{_measureWeight.Name}' has no ratio; configure it in Configuration > Measures.\");\nweight = await _measureService.ConvertFromPrimaryMeasureWeightAsync(weight, _measureWeight);","handlingStrategy":"validation","validationCode":"// Validate before converting from the base weight to a target weight\nvar baseWt = await _measureService.GetMeasureWeightByIdAsync(_measureSettings.BaseWeightId);\nif (value != decimal.Zero && targetMeasureWeight.Id != baseWt.Id && targetMeasureWeight.Ratio == decimal.Zero)\n    throw new InvalidOperationException($\"Configure a non-zero Ratio for weight '{targetMeasureWeight.Name}'.\");\nvar converted = await _measureService.ConvertFromPrimaryMeasureWeightAsync(value, targetMeasureWeight);","typeGuard":"static bool IsTargetWeightConvertible(MeasureWeight target, MeasureWeight baseWt, decimal value)\n    => value == decimal.Zero || target.Id == baseWt.Id || target.Ratio != decimal.Zero;","tryCatchPattern":"try { weight = await _measureService.ConvertFromPrimaryMeasureWeightAsync(weight, targetWt); }\ncatch (NopException ex) when (ex.Message.StartsWith(\"Exchange ratio not set for weight\"))\n{ /* report 'configure the target weight ratio'; do not silently return value */ }","preventionTips":["When configuring a shipping plugin that converts weights, verify its MeasureWeight has a non-zero Ratio.","Keep a startup health check that asserts all published weights have Ratio != 0.","After restoring a DB, re-verify weight ratios before enabling shipping."],"tags":["measure","weight","shipping","configuration","nopcommerce"],"backgroundTag":null,"analyzedSha":"64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2","analyzedAt":"2026-08-13T21:19:38.062Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}