diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp
index 5e23537afde..e5f26d55088 100644
--- a/src/mongo/db/catalog/coll_mod.cpp
+++ b/src/mongo/db/catalog/coll_mod.cpp
@@ -1054,6 +1054,14 @@ Status _collModInternal(OperationContext* opCtx,
         std::vector<std::string> indexesWithInvalidOptions =
             writableColl->repairInvalidIndexOptions(opCtx);
         for (const auto& indexWithInvalidOptions : indexesWithInvalidOptions) {
+            // @HERE is where we use 'coll', which holds an older state of the index catalog, to
+            // fetch the index entry.
+            //
+            // The bug is resolved by obtaining the index descriptor via 'writableColl' instead.
+            // const IndexDescriptor* desc =
+            //      writableColl->getIndexCatalog()->findIndexByName(opCtx,
+            //          indexWithInvalidOptions);
+
             const IndexDescriptor* desc =
                 coll->getIndexCatalog()->findIndexByName(opCtx, indexWithInvalidOptions);
             invariant(desc);
diff --git a/src/mongo/db/catalog/index_key_validate.cpp b/src/mongo/db/catalog/index_key_validate.cpp
index 67b907f80fd..a16116e4604 100644
--- a/src/mongo/db/catalog/index_key_validate.cpp
+++ b/src/mongo/db/catalog/index_key_validate.cpp
@@ -100,6 +100,7 @@ namespace {
 // names will be disabled. This will allow for creation of indexes with invalid field names in their
 // specification.
 MONGO_FAIL_POINT_DEFINE(skipIndexCreateFieldNameValidation);
+MONGO_FAIL_POINT_DEFINE(skipIndexCreateWeightsFieldValidation);
 
 // When the skipTTLIndexExpireAfterSecondsValidation failpoint is enabled,
 // validation for TTL index 'expireAfterSeconds' will be disabled in certain codepaths.
@@ -706,10 +707,12 @@ StatusWith<BSONObj> validateIndexSpec(OperationContext* opCtx, const BSONObj& in
     }
 
     if (indexType != IndexNames::TEXT && hasWeightsField) {
-        return {ErrorCodes::CannotCreateIndex,
-                str::stream() << "Invalid index specification " << indexSpec << "; the field '"
-                              << IndexDescriptor::kWeightsFieldName
-                              << "' can only be specified with text indexes"};
+        if (!skipIndexCreateWeightsFieldValidation.shouldFail()) {
+            return {ErrorCodes::CannotCreateIndex,
+                    str::stream() << "Invalid index specification " << indexSpec << "; the field '"
+                                  << IndexDescriptor::kWeightsFieldName
+                                  << "' can only be specified with text indexes"};
+        }
     }
 
     if (unique && prepareUnique) {
diff --git a/ttl_fixer_segfault_repro.js b/ttl_fixer_segfault_repro.js
new file mode 100644
index 00000000000..fd4d0c05651
--- /dev/null
+++ b/ttl_fixer_segfault_repro.js
@@ -0,0 +1,86 @@
+/**
+ * Reproduces a seg-fault caused by the InvalidTTLIndexFixer trying to 'fix' an invalid TTL index
+ * spec with both a non-int 'expireAfterSeconds' field and an unexpected additional field.
+ * Specifically, the behavior is caused by the additional field being an accepted field for text
+ * indexes, 'weights', but not indexes of other types.
+ *
+ * The original issue occured when trying to upgrade from an older version, so the first steps are
+ * to bypass validation checks and introduce an invalid ttl index spec.
+ *
+ * @tags: [
+ *     requires_replication,
+ * ]
+ */
+import {configureFailPoint} from "jstests/libs/fail_point_util.js";
+
+const rst = new ReplSetTest({
+    nodes: [{}, {rsConfig: {votes: 0, priority: 0}}],
+    nodeOptions: {setParameter: {ttlMonitorSleepSecs: 1}},
+});
+rst.startSet();
+rst.initiate();
+
+let primary = rst.getPrimary();
+let secondary = rst.getSecondary();
+const db = primary.getDB('test');
+const expireAfterSecondsNonInt = 100.3;
+let coll = db.t;
+assert.commandWorked(coll.insert({_id: 0, t: ISODate()}));
+
+// Failpoints to circumvent validation when introducing the invalid index. It's possible we don't
+// need all of them. 'skipIndexCreateWeightsFieldValidation' is the most important.
+const fpNames = [
+    'skipTTLIndexValidationOnCreateIndex',
+    'skipTTLIndexExpireAfterSecondsValidation',
+    'skipIndexCreateFieldNameValidation',
+    'skipIndexCreateWeightsFieldValidation',
+];
+const fps = [];
+for (const fpName of fpNames) {
+    fps.push(configureFailPoint(primary, fpName));
+    fps.push(configureFailPoint(secondary, fpName));
+}
+try {
+    assert.commandWorked(
+        coll.createIndex({t: 1}, {expireAfterSeconds: expireAfterSecondsNonInt, weights: {}}));
+    const catalogContents = coll.aggregate([{$listCatalog: {}}]).toArray();
+    jsTestLog("Catalog contents: " + tojson(catalogContents));
+
+    rst.awaitReplication();
+    rst.awaitLastStableRecoveryTimestamp();
+} finally {
+    for (const fp of fps) {
+        fp.off();
+    }
+}
+
+// @HERE: when the primary steps back up, we eventually trigger the seg-fault.
+jsTest.log(
+    `Forcing the primary to step down then step up again to trigger 'InvalidTTLIndexFixer' thread`);
+assert.commandWorked(primary.adminCommand({replSetStepDown: 5, force: true}));
+primary = rst.waitForPrimary();
+
+coll = primary.getDB(db.getName()).getCollection(coll.getName());
+jsTestLog("Catalog contents on primary: " + tojson(coll.aggregate([{$listCatalog: {}}]).toArray()));
+
+// Ensure the 'InvalidTTLIndexFixer' thread has time to run.
+assert.soon(
+    () => {
+        return 1 ==
+            rst.findOplog(primary,
+                          {
+                              op: 'c',
+                              ns: coll.getDB().getCollection('$cmd').getFullName(),
+                              'o.collMod': coll.getName(),
+                              'o.index.name': 't_1',
+                              'o.index.expireAfterSeconds': Math.floor(expireAfterSecondsNonInt),
+                          },
+                          /*limit=*/ 1)
+                .toArray()
+                .length;
+    },
+    'TTL index with ' + expireAfterSecondsNonInt +
+        ' expireAfterSeconds was not fixed using collMod during step-up: ' +
+        tojson(rst.findOplog(primary, {op: {$ne: 'n'}}, /*limit=*/ 10).toArray()));
+rst.awaitReplication();
+rst.stopSet();
