diff --git a/bridges/snowbridge/pallets/inbound-queue/src/test.rs b/bridges/snowbridge/pallets/inbound-queue/src/test.rs
index 76d0b98e9eb4..5386b845f2ec 100644
--- a/bridges/snowbridge/pallets/inbound-queue/src/test.rs
+++ b/bridges/snowbridge/pallets/inbound-queue/src/test.rs
@@ -40,8 +40,8 @@ fn test_submit_happy_path() {
 				.into(),
 			nonce: 1,
 			message_id: [
-				11, 25, 133, 51, 23, 68, 111, 211, 132, 94, 254, 17, 194, 252, 198, 233, 10, 193,
-				156, 93, 72, 140, 65, 69, 79, 155, 154, 28, 141, 166, 171, 255,
+				97, 161, 116, 204, 182, 115, 192, 144, 130, 243, 240, 193, 122, 154, 108, 91, 247,
+				41, 226, 237, 202, 158, 238, 239, 210, 8, 147, 131, 84, 146, 171, 176,
 			],
 			fee_burned: 110000000000,
 		}
diff --git a/bridges/snowbridge/primitives/router/src/inbound/mod.rs b/bridges/snowbridge/primitives/router/src/inbound/mod.rs
index e03560f66e24..54a578b988a4 100644
--- a/bridges/snowbridge/primitives/router/src/inbound/mod.rs
+++ b/bridges/snowbridge/primitives/router/src/inbound/mod.rs
@@ -279,6 +279,7 @@ where
 			// Call create_asset on foreign assets pallet.
 			Transact {
 				origin_kind: OriginKind::Xcm,
+				fallback_max_weight: None,
 				call: (
 					create_call_index,
 					asset_id,
diff --git a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs
index 9125c976525e..380f4983ad98 100644
--- a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs
+++ b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs
@@ -31,7 +31,7 @@ pub fn xcm_transact_paid_execution(
 	VersionedXcm::from(Xcm(vec![
 		WithdrawAsset(fees.clone().into()),
 		BuyExecution { fees, weight_limit },
-		Transact { origin_kind, call },
+		Transact { origin_kind, call, fallback_max_weight: None },
 		RefundSurplus,
 		DepositAsset {
 			assets: All.into(),
@@ -53,7 +53,7 @@ pub fn xcm_transact_unpaid_execution(
 
 	VersionedXcm::from(Xcm(vec![
 		UnpaidExecution { weight_limit, check_origin },
-		Transact { origin_kind, call },
+		Transact { origin_kind, call, fallback_max_weight: None },
 	]))
 }
 
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/transact.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/transact.rs
index 3c53cfb261be..592c2845255c 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/transact.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/transact.rs
@@ -43,7 +43,7 @@ fn transfer_and_transact_in_same_xcm(
 
 	// xcm to be executed at dest
 	let xcm_on_dest = Xcm(vec![
-		Transact { origin_kind: OriginKind::Xcm, call },
+		Transact { origin_kind: OriginKind::Xcm, call, fallback_max_weight: None },
 		ExpectTransactStatus(MaybeErrorCode::Success),
 		// since this is the last hop, we don't need to further use any assets previously
 		// reserved for fees (there are no further hops to cover transport fees for); we
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
index d59553574c26..c72d5045ddc0 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
@@ -84,7 +84,11 @@ fn create_agent() {
 	let remote_xcm = VersionedXcm::from(Xcm(vec![
 		UnpaidExecution { weight_limit: Unlimited, check_origin: None },
 		DescendOrigin(Parachain(origin_para).into()),
-		Transact { origin_kind: OriginKind::Xcm, call: create_agent_call.encode().into() },
+		Transact {
+			origin_kind: OriginKind::Xcm,
+			call: create_agent_call.encode().into(),
+			fallback_max_weight: None,
+		},
 	]));
 
 	// Rococo Global Consensus
@@ -138,7 +142,11 @@ fn create_channel() {
 	let create_agent_xcm = VersionedXcm::from(Xcm(vec![
 		UnpaidExecution { weight_limit: Unlimited, check_origin: None },
 		DescendOrigin(Parachain(origin_para).into()),
-		Transact { origin_kind: OriginKind::Xcm, call: create_agent_call.encode().into() },
+		Transact {
+			origin_kind: OriginKind::Xcm,
+			call: create_agent_call.encode().into(),
+			fallback_max_weight: None,
+		},
 	]));
 
 	let create_channel_call =
@@ -147,7 +155,11 @@ fn create_channel() {
 	let create_channel_xcm = VersionedXcm::from(Xcm(vec![
 		UnpaidExecution { weight_limit: Unlimited, check_origin: None },
 		DescendOrigin(Parachain(origin_para).into()),
-		Transact { origin_kind: OriginKind::Xcm, call: create_channel_call.encode().into() },
+		Transact {
+			origin_kind: OriginKind::Xcm,
+			call: create_channel_call.encode().into(),
+			fallback_max_weight: None,
+		},
 	]));
 
 	// Rococo Global Consensus
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/transact.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/transact.rs
index db42704dae61..7831c8d66357 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/transact.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/transact.rs
@@ -49,7 +49,7 @@ fn transfer_and_transact_in_same_xcm(
 
 	// xcm to be executed at dest
 	let xcm_on_dest = Xcm(vec![
-		Transact { origin_kind: OriginKind::Xcm, call },
+		Transact { origin_kind: OriginKind::Xcm, call, fallback_max_weight: None },
 		ExpectTransactStatus(MaybeErrorCode::Success),
 		// since this is the last hop, we don't need to further use any assets previously
 		// reserved for fees (there are no further hops to cover transport fees for); we
diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs
index 80b82e0c446f..802fed1e681d 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs
@@ -41,6 +41,7 @@ fn fellows_whitelist_call() {
 					)
 					.encode()
 					.into(),
+					fallback_max_weight: None
 				}
 			]))),
 		});
diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs
index 3dadcdd94870..1ba787aaec52 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs
@@ -48,7 +48,11 @@ fn relay_commands_add_registrar() {
 			dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))),
 			message: bx!(VersionedXcm::from(Xcm(vec![
 				UnpaidExecution { weight_limit: Unlimited, check_origin: None },
-				Transact { origin_kind, call: add_registrar_call.encode().into() }
+				Transact {
+					origin_kind,
+					call: add_registrar_call.encode().into(),
+					fallback_max_weight: None
+				}
 			]))),
 		});
 
@@ -107,7 +111,11 @@ fn relay_commands_add_registrar_wrong_origin() {
 				dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))),
 				message: bx!(VersionedXcm::from(Xcm(vec![
 					UnpaidExecution { weight_limit: Unlimited, check_origin: None },
-					Transact { origin_kind, call: add_registrar_call.encode().into() }
+					Transact {
+						origin_kind,
+						call: add_registrar_call.encode().into(),
+						fallback_max_weight: None
+					}
 				]))),
 			});
 
@@ -194,7 +202,11 @@ fn relay_commands_kill_identity() {
 			dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))),
 			message: bx!(VersionedXcm::from(Xcm(vec![
 				UnpaidExecution { weight_limit: Unlimited, check_origin: None },
-				Transact { origin_kind, call: kill_identity_call.encode().into() }
+				Transact {
+					origin_kind,
+					call: kill_identity_call.encode().into(),
+					fallback_max_weight: None
+				}
 			]))),
 		});
 
@@ -252,7 +264,11 @@ fn relay_commands_kill_identity_wrong_origin() {
 				dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))),
 				message: bx!(VersionedXcm::from(Xcm(vec![
 					UnpaidExecution { weight_limit: Unlimited, check_origin: None },
-					Transact { origin_kind, call: kill_identity_call.encode().into() }
+					Transact {
+						origin_kind,
+						call: kill_identity_call.encode().into(),
+						fallback_max_weight: None
+					}
 				]))),
 			});
 
@@ -298,7 +314,11 @@ fn relay_commands_add_remove_username_authority() {
 			dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))),
 			message: bx!(VersionedXcm::from(Xcm(vec![
 				UnpaidExecution { weight_limit: Unlimited, check_origin: None },
-				Transact { origin_kind, call: add_username_authority.encode().into() }
+				Transact {
+					origin_kind,
+					call: add_username_authority.encode().into(),
+					fallback_max_weight: None
+				}
 			]))),
 		});
 
@@ -383,7 +403,11 @@ fn relay_commands_add_remove_username_authority() {
 			dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))),
 			message: bx!(VersionedXcm::from(Xcm(vec![
 				UnpaidExecution { weight_limit: Unlimited, check_origin: None },
-				Transact { origin_kind, call: remove_username_authority.encode().into() }
+				Transact {
+					origin_kind,
+					call: remove_username_authority.encode().into(),
+					fallback_max_weight: None
+				}
 			]))),
 		});
 
@@ -443,7 +467,11 @@ fn relay_commands_add_remove_username_authority_wrong_origin() {
 				dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))),
 				message: bx!(VersionedXcm::from(Xcm(vec![
 					UnpaidExecution { weight_limit: Unlimited, check_origin: None },
-					Transact { origin_kind, call: add_username_authority.encode().into() }
+					Transact {
+						origin_kind,
+						call: add_username_authority.encode().into(),
+						fallback_max_weight: None
+					}
 				]))),
 			});
 
@@ -483,6 +511,7 @@ fn relay_commands_add_remove_username_authority_wrong_origin() {
 						Transact {
 							origin_kind: OriginKind::SovereignAccount,
 							call: remove_username_authority.encode().into(),
+							fallback_max_weight: None,
 						}
 					]))),
 				});
diff --git a/cumulus/parachains/pallets/ping/src/lib.rs b/cumulus/parachains/pallets/ping/src/lib.rs
index 2cf32c891fc0..b6423a81db3c 100644
--- a/cumulus/parachains/pallets/ping/src/lib.rs
+++ b/cumulus/parachains/pallets/ping/src/lib.rs
@@ -114,6 +114,7 @@ pub mod pallet {
 						})
 						.encode()
 						.into(),
+						fallback_max_weight: None,
 					}]),
 				) {
 					Ok((hash, cost)) => {
@@ -214,6 +215,7 @@ pub mod pallet {
 					})
 					.encode()
 					.into(),
+					fallback_max_weight: None,
 				}]),
 			) {
 				Ok((hash, cost)) =>
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs
index 025c39bcee07..74f564037400 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs
@@ -84,7 +84,11 @@ impl<Call> XcmWeightInfo<Call> for AssetHubRococoXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
+	fn transact(
+		_origin_type: &OriginKind,
+		_fallback_max_weight: &Option<Weight>,
+		_call: &DoubleEncoded<Call>,
+	) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs
index 35ff2dc367c0..ff99f1242b22 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs
@@ -83,7 +83,11 @@ impl<Call> XcmWeightInfo<Call> for AssetHubWestendXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
+	fn transact(
+		_origin_type: &OriginKind,
+		_fallback_max_weight: &Option<Weight>,
+		_call: &DoubleEncoded<Call>,
+	) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
index aeacc1a5471e..b1577e0ca7f6 100644
--- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
+++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
@@ -1205,14 +1205,20 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor
 			let xcm = Xcm(vec![
 				WithdrawAsset(buy_execution_fee.clone().into()),
 				BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
-				Transact { origin_kind: OriginKind::Xcm, call: foreign_asset_create.into() },
+				Transact {
+					origin_kind: OriginKind::Xcm,
+					call: foreign_asset_create.into(),
+					fallback_max_weight: None,
+				},
 				Transact {
 					origin_kind: OriginKind::SovereignAccount,
 					call: foreign_asset_set_metadata.into(),
+					fallback_max_weight: None,
 				},
 				Transact {
 					origin_kind: OriginKind::SovereignAccount,
 					call: foreign_asset_set_team.into(),
+					fallback_max_weight: None,
 				},
 				ExpectTransactStatus(MaybeErrorCode::Success),
 			]);
@@ -1318,7 +1324,11 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor
 			let xcm = Xcm(vec![
 				WithdrawAsset(buy_execution_fee.clone().into()),
 				BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
-				Transact { origin_kind: OriginKind::Xcm, call: foreign_asset_create.into() },
+				Transact {
+					origin_kind: OriginKind::Xcm,
+					call: foreign_asset_create.into(),
+					fallback_max_weight: None,
+				},
 				ExpectTransactStatus(MaybeErrorCode::from(DispatchError::BadOrigin.encode())),
 			]);
 
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs
index 288aac38563c..e5c6f493d6dc 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs
@@ -84,7 +84,11 @@ impl<Call> XcmWeightInfo<Call> for BridgeHubRococoXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
+	fn transact(
+		_origin_type: &OriginKind,
+		_fallback_max_weight: &Option<Weight>,
+		_call: &DoubleEncoded<Call>,
+	) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs
index fa1304d11c6f..939b1c7a287b 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs
@@ -85,7 +85,11 @@ impl<Call> XcmWeightInfo<Call> for BridgeHubWestendXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
+	fn transact(
+		_origin_type: &OriginKind,
+		_fallback_max_weight: &Option<Weight>,
+		_call: &DoubleEncoded<Call>,
+	) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs
index d76ac443a147..35c3dd8836a8 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs
@@ -135,6 +135,7 @@ impl CoretimeInterface for CoretimeAllocator {
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
 				call: request_core_count_call.encode().into(),
+				fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)),
 			},
 		]);
 
@@ -164,6 +165,7 @@ impl CoretimeInterface for CoretimeAllocator {
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
 				call: request_revenue_info_at_call.encode().into(),
+				fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)),
 			},
 		]);
 
@@ -192,6 +194,7 @@ impl CoretimeInterface for CoretimeAllocator {
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
 				call: credit_account_call.encode().into(),
+				fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)),
 			},
 		]);
 
@@ -256,6 +259,7 @@ impl CoretimeInterface for CoretimeAllocator {
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
 				call: assign_core_call.encode().into(),
+				fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)),
 			},
 		]);
 
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs
index f69736e31451..2c4a97601c64 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs
@@ -84,7 +84,11 @@ impl<Call> XcmWeightInfo<Call> for CoretimeRococoXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
+	fn transact(
+		_origin_type: &OriginKind,
+		_fallback_max_weight: &Option<Weight>,
+		_call: &DoubleEncoded<Call>,
+	) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs
index f0c03849750a..985e64fb76f9 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs
@@ -127,6 +127,12 @@ impl CoretimeInterface for CoretimeAllocator {
 		use crate::coretime::CoretimeProviderCalls::RequestCoreCount;
 		let request_core_count_call = RelayRuntimePallets::Coretime(RequestCoreCount(count));
 
+		// Weight for `request_core_count` from westend benchmarks:
+		// `ref_time` = 7889000 + (3 * 25000000) + (1 * 100000000) = 182889000
+		// `proof_size` = 1636
+		// Add 5% to each component and round to 2 significant figures.
+		let call_weight = Weight::from_parts(190_000_000, 1700);
+
 		let message = Xcm(vec![
 			Instruction::UnpaidExecution {
 				weight_limit: WeightLimit::Unlimited,
@@ -135,6 +141,7 @@ impl CoretimeInterface for CoretimeAllocator {
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
 				call: request_core_count_call.encode().into(),
+				fallback_max_weight: Some(call_weight),
 			},
 		]);
 
@@ -164,6 +171,7 @@ impl CoretimeInterface for CoretimeAllocator {
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
 				call: request_revenue_info_at_call.encode().into(),
+				fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)),
 			},
 		]);
 
@@ -192,6 +200,7 @@ impl CoretimeInterface for CoretimeAllocator {
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
 				call: credit_account_call.encode().into(),
+				fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)),
 			},
 		]);
 
@@ -216,6 +225,12 @@ impl CoretimeInterface for CoretimeAllocator {
 	) {
 		use crate::coretime::CoretimeProviderCalls::AssignCore;
 
+		// Weight for `assign_core` from westend benchmarks:
+		// `ref_time` = 10177115 + (1 * 25000000) + (2 * 100000000) + (57600 * 13932) = 937660315
+		// `proof_size` = 3612
+		// Add 5% to each component and round to 2 significant figures.
+		let call_weight = Weight::from_parts(980_000_000, 3800);
+
 		// The relay chain currently only allows `assign_core` to be called with a complete mask
 		// and only ever with increasing `begin`. The assignments must be truncated to avoid
 		// dropping that core's assignment completely.
@@ -256,6 +271,7 @@ impl CoretimeInterface for CoretimeAllocator {
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
 				call: assign_core_call.encode().into(),
+				fallback_max_weight: Some(call_weight),
 			},
 		]);
 
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs
index 1640baa38c99..906088a1df86 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs
@@ -83,7 +83,11 @@ impl<Call> XcmWeightInfo<Call> for CoretimeWestendXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
+	fn transact(
+		_origin_type: &OriginKind,
+		_fallback_max_weight: &Option<Weight>,
+		_call: &DoubleEncoded<Call>,
+	) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs
index 631cc7b7f0b0..47008a2943e5 100644
--- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs
@@ -83,7 +83,11 @@ impl<Call> XcmWeightInfo<Call> for PeopleRococoXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
+	fn transact(
+		_origin_type: &OriginKind,
+		_fallback_max_weight: &Option<Weight>,
+		_call: &DoubleEncoded<Call>,
+	) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs
index 4b51a3ba411b..27fd499ebba7 100644
--- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs
@@ -83,7 +83,11 @@ impl<Call> XcmWeightInfo<Call> for PeopleWestendXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
+	fn transact(
+		_origin_type: &OriginKind,
+		_fallback_max_weight: &Option<Weight>,
+		_call: &DoubleEncoded<Call>,
+	) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs
index 3f2e721d13f6..5c33809ba67b 100644
--- a/cumulus/parachains/runtimes/test-utils/src/lib.rs
+++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs
@@ -445,7 +445,11 @@ impl<
 		// prepare xcm as governance will do
 		let xcm = Xcm(vec![
 			UnpaidExecution { weight_limit: Unlimited, check_origin: None },
-			Transact { origin_kind: OriginKind::Superuser, call: call.into() },
+			Transact {
+				origin_kind: OriginKind::Superuser,
+				call: call.into(),
+				fallback_max_weight: None,
+			},
 			ExpectTransactStatus(MaybeErrorCode::Success),
 		]);
 
@@ -476,7 +480,7 @@ impl<
 
 		// prepare `Transact` xcm
 		instructions.extend(vec![
-			Transact { origin_kind, call: call.encode().into() },
+			Transact { origin_kind, call: call.encode().into(), fallback_max_weight: None },
 			ExpectTransactStatus(MaybeErrorCode::Success),
 		]);
 		let xcm = Xcm(instructions);
diff --git a/polkadot/runtime/parachains/src/coretime/mod.rs b/polkadot/runtime/parachains/src/coretime/mod.rs
index 966b7997a277..5656e92b90be 100644
--- a/polkadot/runtime/parachains/src/coretime/mod.rs
+++ b/polkadot/runtime/parachains/src/coretime/mod.rs
@@ -136,6 +136,11 @@ pub mod pallet {
 		type AssetTransactor: TransactAsset;
 		/// AccountId to Location converter
 		type AccountToLocation: for<'a> TryConvert<&'a Self::AccountId, Location>;
+
+		/// Maximum weight for any XCM transact call that should be executed on the coretime chain.
+		///
+		/// Basically should be `max_weight(set_leases, reserve, notify_core_count)`.
+		type MaxXcmTransactWeight: Get<Weight>;
 	}
 
 	#[pallet::event]
@@ -333,6 +338,7 @@ impl<T: Config> OnNewSession<BlockNumberFor<T>> for Pallet<T> {
 fn mk_coretime_call<T: Config>(call: crate::coretime::CoretimeCalls) -> Instruction<()> {
 	Instruction::Transact {
 		origin_kind: OriginKind::Superuser,
+		fallback_max_weight: Some(T::MaxXcmTransactWeight::get()),
 		call: BrokerRuntimePallets::Broker(call).encode().into(),
 	}
 }
diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs
index d701e1f9bd80..ee1990a7b618 100644
--- a/polkadot/runtime/parachains/src/mock.rs
+++ b/polkadot/runtime/parachains/src/mock.rs
@@ -421,6 +421,7 @@ impl assigner_coretime::Config for Test {}
 
 parameter_types! {
 	pub const BrokerId: u32 = 10u32;
+	pub MaxXcmTransactWeight: Weight = Weight::from_parts(10_000_000, 10_000);
 }
 
 pub struct BrokerPot;
@@ -437,6 +438,7 @@ impl coretime::Config for Test {
 	type BrokerId = BrokerId;
 	type WeightInfo = crate::coretime::TestWeightInfo;
 	type SendXcm = DummyXcmSender;
+	type MaxXcmTransactWeight = MaxXcmTransactWeight;
 	type BrokerPotLocation = BrokerPot;
 	type AssetTransactor = ();
 	type AccountToLocation = ();
diff --git a/polkadot/runtime/rococo/src/impls.rs b/polkadot/runtime/rococo/src/impls.rs
index ab796edc54b1..7d7e9fa9f06c 100644
--- a/polkadot/runtime/rococo/src/impls.rs
+++ b/polkadot/runtime/rococo/src/impls.rs
@@ -21,7 +21,7 @@ use core::marker::PhantomData;
 use frame_support::pallet_prelude::DispatchResult;
 use frame_system::RawOrigin;
 use polkadot_primitives::Balance;
-use polkadot_runtime_common::identity_migrator::OnReapIdentity;
+use polkadot_runtime_common::identity_migrator::{OnReapIdentity, WeightInfo};
 use rococo_runtime_constants::currency::*;
 use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm};
 use xcm_executor::traits::TransactAsset;
@@ -88,7 +88,10 @@ where
 	AccountId: Into<[u8; 32]> + Clone + Encode,
 {
 	fn on_reap_identity(who: &AccountId, fields: u32, subs: u32) -> DispatchResult {
-		use crate::impls::IdentityMigratorCalls::PokeDeposit;
+		use crate::{
+			impls::IdentityMigratorCalls::PokeDeposit,
+			weights::polkadot_runtime_common_identity_migrator::WeightInfo as MigratorWeights,
+		};
 
 		let total_to_send = Self::calculate_remote_deposit(fields, subs);
 
@@ -141,6 +144,7 @@ where
 				.into();
 
 		let poke = PeopleRuntimePallets::<AccountId>::IdentityMigrator(PokeDeposit(who.clone()));
+		let remote_weight_limit = MigratorWeights::<Runtime>::poke_deposit().saturating_mul(2);
 
 		// Actual program to execute on People Chain.
 		let program: Xcm<()> = Xcm(vec![
@@ -157,7 +161,11 @@ where
 					.into(),
 			},
 			// Poke the deposit to reserve the appropriate amount on the parachain.
-			Transact { origin_kind: OriginKind::Superuser, call: poke.encode().into() },
+			Transact {
+				origin_kind: OriginKind::Superuser,
+				fallback_max_weight: Some(remote_weight_limit),
+				call: poke.encode().into(),
+			},
 		]);
 
 		// send
diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs
index 5da9da86f02e..c832ace91c07 100644
--- a/polkadot/runtime/rococo/src/lib.rs
+++ b/polkadot/runtime/rococo/src/lib.rs
@@ -1100,6 +1100,7 @@ impl parachains_scheduler::Config for Runtime {
 parameter_types! {
 	pub const BrokerId: u32 = BROKER_ID;
 	pub const BrokerPalletId: PalletId = PalletId(*b"py/broke");
+	pub MaxXcmTransactWeight: Weight = Weight::from_parts(200_000_000, 20_000);
 }
 
 pub struct BrokerPot;
@@ -1123,6 +1124,7 @@ impl coretime::Config for Runtime {
 		xcm_config::ThisNetwork,
 		<Runtime as frame_system::Config>::AccountId,
 	>;
+	type MaxXcmTransactWeight = MaxXcmTransactWeight;
 }
 
 parameter_types! {
diff --git a/polkadot/runtime/rococo/src/weights/xcm/mod.rs b/polkadot/runtime/rococo/src/weights/xcm/mod.rs
index a28b46800874..16f51a778917 100644
--- a/polkadot/runtime/rococo/src/weights/xcm/mod.rs
+++ b/polkadot/runtime/rococo/src/weights/xcm/mod.rs
@@ -111,7 +111,11 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for RococoXcmWeight<RuntimeCall> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmBalancesWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(_origin_kind: &OriginKind, _call: &DoubleEncoded<RuntimeCall>) -> Weight {
+	fn transact(
+		_origin_kind: &OriginKind,
+		_fallback_max_weight: &Option<Weight>,
+		_call: &DoubleEncoded<RuntimeCall>,
+	) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs
index 69ce187dce40..d4031f7ac57a 100644
--- a/polkadot/runtime/test-runtime/src/lib.rs
+++ b/polkadot/runtime/test-runtime/src/lib.rs
@@ -584,6 +584,7 @@ impl parachains_paras::Config for Runtime {
 
 parameter_types! {
 	pub const BrokerId: u32 = 10u32;
+	pub MaxXcmTransactWeight: Weight = Weight::from_parts(10_000_000, 10_000);
 }
 
 pub struct BrokerPot;
@@ -657,6 +658,7 @@ impl coretime::Config for Runtime {
 	type BrokerId = BrokerId;
 	type WeightInfo = crate::coretime::TestWeightInfo;
 	type SendXcm = DummyXcmSender;
+	type MaxXcmTransactWeight = MaxXcmTransactWeight;
 	type BrokerPotLocation = BrokerPot;
 	type AssetTransactor = ();
 	type AccountToLocation = ();
diff --git a/polkadot/runtime/westend/src/impls.rs b/polkadot/runtime/westend/src/impls.rs
index d7281dad56d4..8cb597cbaa95 100644
--- a/polkadot/runtime/westend/src/impls.rs
+++ b/polkadot/runtime/westend/src/impls.rs
@@ -21,7 +21,7 @@ use core::marker::PhantomData;
 use frame_support::pallet_prelude::DispatchResult;
 use frame_system::RawOrigin;
 use polkadot_primitives::Balance;
-use polkadot_runtime_common::identity_migrator::OnReapIdentity;
+use polkadot_runtime_common::identity_migrator::{OnReapIdentity, WeightInfo};
 use westend_runtime_constants::currency::*;
 use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm};
 use xcm_executor::traits::TransactAsset;
@@ -88,7 +88,10 @@ where
 	AccountId: Into<[u8; 32]> + Clone + Encode,
 {
 	fn on_reap_identity(who: &AccountId, fields: u32, subs: u32) -> DispatchResult {
-		use crate::impls::IdentityMigratorCalls::PokeDeposit;
+		use crate::{
+			impls::IdentityMigratorCalls::PokeDeposit,
+			weights::polkadot_runtime_common_identity_migrator::WeightInfo as MigratorWeights,
+		};
 
 		let total_to_send = Self::calculate_remote_deposit(fields, subs);
 
@@ -141,6 +144,7 @@ where
 				.into();
 
 		let poke = PeopleRuntimePallets::<AccountId>::IdentityMigrator(PokeDeposit(who.clone()));
+		let remote_weight_limit = MigratorWeights::<Runtime>::poke_deposit().saturating_mul(2);
 
 		// Actual program to execute on People Chain.
 		let program: Xcm<()> = Xcm(vec![
@@ -157,7 +161,11 @@ where
 					.into(),
 			},
 			// Poke the deposit to reserve the appropriate amount on the parachain.
-			Transact { origin_kind: OriginKind::Superuser, call: poke.encode().into() },
+			Transact {
+				origin_kind: OriginKind::Superuser,
+				call: poke.encode().into(),
+				fallback_max_weight: Some(remote_weight_limit),
+			},
 		]);
 
 		// send
diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs
index 9f0b701f20be..f25ed33012a2 100644
--- a/polkadot/runtime/westend/src/lib.rs
+++ b/polkadot/runtime/westend/src/lib.rs
@@ -1326,6 +1326,7 @@ impl parachains_scheduler::Config for Runtime {
 parameter_types! {
 	pub const BrokerId: u32 = BROKER_ID;
 	pub const BrokerPalletId: PalletId = PalletId(*b"py/broke");
+	pub MaxXcmTransactWeight: Weight = Weight::from_parts(200_000_000, 20_000);
 }
 
 pub struct BrokerPot;
@@ -1349,6 +1350,7 @@ impl coretime::Config for Runtime {
 		xcm_config::ThisNetwork,
 		<Runtime as frame_system::Config>::AccountId,
 	>;
+	type MaxXcmTransactWeight = MaxXcmTransactWeight;
 }
 
 parameter_types! {
diff --git a/polkadot/runtime/westend/src/weights/xcm/mod.rs b/polkadot/runtime/westend/src/weights/xcm/mod.rs
index 5be9bad824da..60265445334d 100644
--- a/polkadot/runtime/westend/src/weights/xcm/mod.rs
+++ b/polkadot/runtime/westend/src/weights/xcm/mod.rs
@@ -114,7 +114,11 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for WestendXcmWeight<RuntimeCall> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmBalancesWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(_origin_kind: &OriginKind, _call: &DoubleEncoded<RuntimeCall>) -> Weight {
+	fn transact(
+		_origin_kind: &OriginKind,
+		_fallback_max_weight: &Option<Weight>,
+		_call: &DoubleEncoded<RuntimeCall>,
+	) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs
index f4836b7cdde1..285322891c63 100644
--- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs
+++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs
@@ -186,6 +186,7 @@ mod benchmarks {
 		let instruction = Instruction::Transact {
 			origin_kind: OriginKind::SovereignAccount,
 			call: double_encoded_noop_call,
+			fallback_max_weight: None,
 		};
 		let xcm = Xcm(vec![instruction]);
 		#[block]
diff --git a/polkadot/xcm/src/v4/mod.rs b/polkadot/xcm/src/v4/mod.rs
index 9baf58eacfb0..3ae94b6ede88 100644
--- a/polkadot/xcm/src/v4/mod.rs
+++ b/polkadot/xcm/src/v4/mod.rs
@@ -1314,8 +1314,20 @@ impl<Call: Decode + GetDispatchInfo> TryFrom<NewInstruction<Call>> for Instructi
 			HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
 			HrmpChannelClosing { initiator, sender, recipient } =>
 				Self::HrmpChannelClosing { initiator, sender, recipient },
-			Transact { origin_kind, mut call } => {
-				let require_weight_at_most = call.take_decoded()?.get_dispatch_info().call_weight;
+			Transact { origin_kind, mut call, fallback_max_weight } => {
+				// We first try to decode the call, if we can't, we use the fallback weight,
+				// if there's no fallback, we just return `Weight::MAX`.
+				let require_weight_at_most = match call.take_decoded() {
+					Ok(decoded) => decoded.get_dispatch_info().call_weight,
+					Err(error) => {
+						log::error!(
+							target: "xcm::versions::v5Tov4",
+							"Couldn't decode call in Transact: {:?}, using fallback weight.",
+							error,
+						);
+						fallback_max_weight.unwrap_or(Weight::MAX)
+					},
+				};
 				Self::Transact { origin_kind, require_weight_at_most, call: call.into() }
 			},
 			ReportError(response_info) => Self::ReportError(QueryResponseInfo {
diff --git a/polkadot/xcm/src/v5/mod.rs b/polkadot/xcm/src/v5/mod.rs
index 830b23cc44b7..193b82b6c223 100644
--- a/polkadot/xcm/src/v5/mod.rs
+++ b/polkadot/xcm/src/v5/mod.rs
@@ -493,13 +493,21 @@ pub enum Instruction<Call> {
 	///
 	/// - `origin_kind`: The means of expressing the message origin as a dispatch origin.
 	/// - `call`: The encoded transaction to be applied.
+	/// - `fallback_max_weight`: Used for compatibility with previous versions. Corresponds to the
+	///   `require_weight_at_most` parameter in previous versions. If you don't care about
+	///   compatibility you can just put `None`. WARNING: If you do, your XCM might not work with
+	///   older versions. Make sure to dry-run and validate.
 	///
 	/// Safety: No concerns.
 	///
 	/// Kind: *Command*.
 	///
 	/// Errors:
-	Transact { origin_kind: OriginKind, call: DoubleEncoded<Call> },
+	Transact {
+		origin_kind: OriginKind,
+		fallback_max_weight: Option<Weight>,
+		call: DoubleEncoded<Call>,
+	},
 
 	/// A message to notify about a new incoming HRMP channel. This message is meant to be sent by
 	/// the relay-chain to a para.
@@ -1159,7 +1167,8 @@ impl<Call> Instruction<Call> {
 			HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
 			HrmpChannelClosing { initiator, sender, recipient } =>
 				HrmpChannelClosing { initiator, sender, recipient },
-			Transact { origin_kind, call } => Transact { origin_kind, call: call.into() },
+			Transact { origin_kind, call, fallback_max_weight } =>
+				Transact { origin_kind, call: call.into(), fallback_max_weight },
 			ReportError(response_info) => ReportError(response_info),
 			DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary },
 			DepositReserveAsset { assets, dest, xcm } => DepositReserveAsset { assets, dest, xcm },
@@ -1227,7 +1236,8 @@ impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
 			TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary),
 			TransferReserveAsset { assets, dest, xcm } =>
 				W::transfer_reserve_asset(&assets, dest, xcm),
-			Transact { origin_kind, call } => W::transact(origin_kind, call),
+			Transact { origin_kind, fallback_max_weight, call } =>
+				W::transact(origin_kind, fallback_max_weight, call),
 			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
 				W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity),
 			HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient),
@@ -1343,8 +1353,11 @@ impl<Call> TryFrom<OldInstruction<Call>> for Instruction<Call> {
 			HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
 			HrmpChannelClosing { initiator, sender, recipient } =>
 				Self::HrmpChannelClosing { initiator, sender, recipient },
-			Transact { origin_kind, require_weight_at_most: _, call } =>
-				Self::Transact { origin_kind, call: call.into() },
+			Transact { origin_kind, require_weight_at_most, call } => Self::Transact {
+				origin_kind,
+				call: call.into(),
+				fallback_max_weight: Some(require_weight_at_most),
+			},
 			ReportError(response_info) => Self::ReportError(QueryResponseInfo {
 				query_id: response_info.query_id,
 				destination: response_info.destination.try_into().map_err(|_| ())?,
@@ -1577,6 +1590,59 @@ mod tests {
 		assert_eq!(new_xcm, xcm);
 	}
 
+	#[test]
+	fn transact_roundtrip_works() {
+		// We can convert as long as there's a fallback.
+		let xcm = Xcm::<()>(vec![
+			WithdrawAsset((Here, 1u128).into()),
+			Transact {
+				origin_kind: OriginKind::SovereignAccount,
+				call: vec![200, 200, 200].into(),
+				fallback_max_weight: Some(Weight::from_parts(1_000_000, 1_024)),
+			},
+		]);
+		let old_xcm = OldXcm::<()>(vec![
+			OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
+			OldInstruction::Transact {
+				origin_kind: OriginKind::SovereignAccount,
+				call: vec![200, 200, 200].into(),
+				require_weight_at_most: Weight::from_parts(1_000_000, 1_024),
+			},
+		]);
+		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
+		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
+		assert_eq!(new_xcm, xcm);
+
+		// If we have no fallback the resulting message won't know the weight.
+		let xcm_without_fallback = Xcm::<()>(vec![
+			WithdrawAsset((Here, 1u128).into()),
+			Transact {
+				origin_kind: OriginKind::SovereignAccount,
+				call: vec![200, 200, 200].into(),
+				fallback_max_weight: None,
+			},
+		]);
+		let old_xcm = OldXcm::<()>(vec![
+			OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
+			OldInstruction::Transact {
+				origin_kind: OriginKind::SovereignAccount,
+				call: vec![200, 200, 200].into(),
+				require_weight_at_most: Weight::MAX,
+			},
+		]);
+		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm_without_fallback.clone()).unwrap());
+		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
+		let xcm_with_max_weight_fallback = Xcm::<()>(vec![
+			WithdrawAsset((Here, 1u128).into()),
+			Transact {
+				origin_kind: OriginKind::SovereignAccount,
+				call: vec![200, 200, 200].into(),
+				fallback_max_weight: Some(Weight::MAX),
+			},
+		]);
+		assert_eq!(new_xcm, xcm_with_max_weight_fallback);
+	}
+
 	#[test]
 	fn decoding_respects_limit() {
 		let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
diff --git a/polkadot/xcm/src/v5/traits.rs b/polkadot/xcm/src/v5/traits.rs
index dd067b774fcd..71b67e97d5fe 100644
--- a/polkadot/xcm/src/v5/traits.rs
+++ b/polkadot/xcm/src/v5/traits.rs
@@ -428,6 +428,7 @@ pub type SendResult<T> = result::Result<(T, Assets), SendError>;
 /// let message = Xcm(vec![Instruction::Transact {
 ///     origin_kind: OriginKind::Superuser,
 ///     call: call.into(),
+///     fallback_max_weight: None,
 /// }]);
 /// let message_hash = message.using_encoded(sp_io::hashing::blake2_256);
 ///
diff --git a/polkadot/xcm/xcm-builder/src/tests/transacting.rs b/polkadot/xcm/xcm-builder/src/tests/transacting.rs
index 8963e7147fdc..ba932beaeb3d 100644
--- a/polkadot/xcm/xcm-builder/src/tests/transacting.rs
+++ b/polkadot/xcm/xcm-builder/src/tests/transacting.rs
@@ -23,6 +23,7 @@ fn transacting_should_work() {
 	let message = Xcm::<TestCall>(vec![Transact {
 		origin_kind: OriginKind::Native,
 		call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
+		fallback_max_weight: None,
 	}]);
 	let mut hash = fake_message_hash(&message);
 	let weight_limit = Weight::from_parts(60, 60);
@@ -43,6 +44,7 @@ fn transacting_should_respect_max_weight_requirement() {
 	let message = Xcm::<TestCall>(vec![Transact {
 		origin_kind: OriginKind::Native,
 		call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
+		fallback_max_weight: None,
 	}]);
 	let mut hash = fake_message_hash(&message);
 	let weight_limit = Weight::from_parts(60, 60);
@@ -65,6 +67,7 @@ fn transacting_should_refund_weight() {
 		call: TestCall::Any(Weight::from_parts(50, 50), Some(Weight::from_parts(30, 30)))
 			.encode()
 			.into(),
+		fallback_max_weight: None,
 	}]);
 	let mut hash = fake_message_hash(&message);
 	let weight_limit = Weight::from_parts(60, 60);
@@ -96,6 +99,7 @@ fn paid_transacting_should_refund_payment_for_unused_weight() {
 			call: TestCall::Any(Weight::from_parts(50, 50), Some(Weight::from_parts(10, 10)))
 				.encode()
 				.into(),
+			fallback_max_weight: None,
 		},
 		RefundSurplus,
 		DepositAsset { assets: AllCounted(1).into(), beneficiary: one },
@@ -124,6 +128,7 @@ fn report_successful_transact_status_should_work() {
 		Transact {
 			origin_kind: OriginKind::Native,
 			call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
+			fallback_max_weight: None,
 		},
 		ReportTransactStatus(QueryResponseInfo {
 			destination: Parent.into(),
@@ -159,6 +164,7 @@ fn report_failed_transact_status_should_work() {
 		Transact {
 			origin_kind: OriginKind::Native,
 			call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(),
+			fallback_max_weight: None,
 		},
 		ReportTransactStatus(QueryResponseInfo {
 			destination: Parent.into(),
@@ -194,6 +200,7 @@ fn expect_successful_transact_status_should_work() {
 		Transact {
 			origin_kind: OriginKind::Native,
 			call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
+			fallback_max_weight: None,
 		},
 		ExpectTransactStatus(MaybeErrorCode::Success),
 	]);
@@ -212,6 +219,7 @@ fn expect_successful_transact_status_should_work() {
 		Transact {
 			origin_kind: OriginKind::Native,
 			call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(),
+			fallback_max_weight: None,
 		},
 		ExpectTransactStatus(MaybeErrorCode::Success),
 	]);
@@ -238,6 +246,7 @@ fn expect_failed_transact_status_should_work() {
 		Transact {
 			origin_kind: OriginKind::Native,
 			call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(),
+			fallback_max_weight: None,
 		},
 		ExpectTransactStatus(vec![2].into()),
 	]);
@@ -256,6 +265,7 @@ fn expect_failed_transact_status_should_work() {
 		Transact {
 			origin_kind: OriginKind::Native,
 			call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
+			fallback_max_weight: None,
 		},
 		ExpectTransactStatus(vec![2].into()),
 	]);
@@ -282,6 +292,7 @@ fn clear_transact_status_should_work() {
 		Transact {
 			origin_kind: OriginKind::Native,
 			call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(),
+			fallback_max_weight: None,
 		},
 		ClearTransactStatus,
 		ReportTransactStatus(QueryResponseInfo {
diff --git a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs
index 9b918fd7eeed..699a081e4f22 100644
--- a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs
+++ b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs
@@ -79,7 +79,11 @@ fn transact_recursion_limit_works() {
 		Xcm(vec![
 			WithdrawAsset((Here, 1_000).into()),
 			BuyExecution { fees: (Here, 1).into(), weight_limit: Unlimited },
-			Transact { origin_kind: OriginKind::Native, call: call.encode().into() },
+			Transact {
+				origin_kind: OriginKind::Native,
+				call: call.encode().into(),
+				fallback_max_weight: None,
+			},
 		])
 	};
 	let mut call: Option<polkadot_test_runtime::RuntimeCall> = None;
diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs
index 4e051f24050c..11fd4e04761f 100644
--- a/polkadot/xcm/xcm-executor/src/lib.rs
+++ b/polkadot/xcm/xcm-executor/src/lib.rs
@@ -939,7 +939,8 @@ impl<Config: config::Config> XcmExecutor<Config> {
 					Ok(())
 				})
 			},
-			Transact { origin_kind, mut call } => {
+			// `fallback_max_weight` is not used in the executor, it's only for conversions.
+			Transact { origin_kind, mut call, .. } => {
 				// We assume that the Relay-chain is allowed to use transact on this parachain.
 				let origin = self.cloned_origin().ok_or_else(|| {
 					tracing::trace!(
diff --git a/polkadot/xcm/xcm-simulator/example/src/tests.rs b/polkadot/xcm/xcm-simulator/example/src/tests.rs
index bbac44ed8a1f..f971812f4f4d 100644
--- a/polkadot/xcm/xcm-simulator/example/src/tests.rs
+++ b/polkadot/xcm/xcm-simulator/example/src/tests.rs
@@ -47,6 +47,7 @@ fn dmp() {
 			Xcm(vec![Transact {
 				origin_kind: OriginKind::SovereignAccount,
 				call: remark.encode().into(),
+				fallback_max_weight: None,
 			}]),
 		));
 	});
@@ -74,6 +75,7 @@ fn ump() {
 			Xcm(vec![Transact {
 				origin_kind: OriginKind::SovereignAccount,
 				call: remark.encode().into(),
+				fallback_max_weight: None,
 			}]),
 		));
 	});
@@ -101,6 +103,7 @@ fn xcmp() {
 			Xcm(vec![Transact {
 				origin_kind: OriginKind::SovereignAccount,
 				call: remark.encode().into(),
+				fallback_max_weight: None,
 			}]),
 		));
 	});
@@ -388,6 +391,7 @@ fn reserve_asset_class_create_and_reserve_transfer() {
 			)
 			.encode()
 			.into(),
+			fallback_max_weight: None,
 		}]);
 		// Send creation.
 		assert_ok!(RelayChainPalletXcm::send_xcm(Here, Parachain(1), message));
diff --git a/prdoc/pr_6643.prdoc b/prdoc/pr_6643.prdoc
new file mode 100644
index 000000000000..c111f6356519
--- /dev/null
+++ b/prdoc/pr_6643.prdoc
@@ -0,0 +1,47 @@
+title: Added fallback_max_weight to Transact for sending messages to V4 chains
+doc:
+- audience: Runtime Dev
+  description: |-
+    Removing the `require_weight_at_most` parameter in V5 Transact introduced a problem when converting a message from V5 to V4 to send to chains that didn't upgrade yet.
+    The local chain doesn't know how to decode calls for remote chains so it can't automatically populate `require_weight_at_most` required by V4 Transact.
+    To fix this, XCM v5 Transact now also takes a `fallback_max_weight: Option<Weight>` parameter.
+    This can be set to `None` if the instruction is not meant to be sent to chains running XCM versions lower than V5.
+    If set to `Some(weight)`, a subsequent conversion to V4 will result in `Transact { require_weight_at_most: weight, .. }`.
+    The plan is to remove this workaround in V6 since there will be a good conversion path from V6 to V5.
+crates:
+- name: snowbridge-router-primitives
+  bump: major
+- name: emulated-integration-tests-common
+  bump: major
+- name: asset-hub-rococo-runtime
+  bump: major
+- name: asset-hub-westend-runtime
+  bump: major
+- name: asset-test-utils
+  bump: major
+- name: bridge-hub-rococo-runtime
+  bump: major
+- name: bridge-hub-westend-runtime
+  bump: major
+- name: coretime-rococo-runtime
+  bump: major
+- name: coretime-westend-runtime
+  bump: major
+- name: people-rococo-runtime
+  bump: major
+- name: people-westend-runtime
+  bump: major
+- name: parachains-runtimes-test-utils
+  bump: major
+- name: polkadot-runtime-parachains
+  bump: major
+- name: rococo-runtime
+  bump: major
+- name: westend-runtime
+  bump: major
+- name: staging-xcm
+  bump: major
+- name: staging-xcm-builder
+  bump: major
+- name: staging-xcm-executor
+  bump: major