• Type: Bug
    • Resolution: Unresolved
    • Priority: Major - P3
    • None
    • Affects Version/s: None
    • Component/s: None
    • None
    • Cluster Scalability
    • ALL
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      Symptom

      analyzeShardKey on a valid, all-ascending candidate key fails with a BadValue error that quotes an index pattern the caller never submitted, when the collection carries a prefix-matching index with a descending field.

      Observed against sample_supplies.sales (the Atlas sample dataset) with the candidate key {"purchaseMethod": 1} on a collection carrying the index purchaseMethod_1_saleDate_1_storeLocation_-1:

      (BadValue) Shard key { purchaseMethod: 1, saleDate: 1, storeLocation: -1 } is invalid.
      Non-hashed fields must be set to a value of 1 (ascending). Failed to parse field storeLocation
      

      The candidate key is legal. The rejected pattern is the collection's index.

      Reproduction

      db.sales.createIndex({purchaseMethod: 1, saleDate: 1, storeLocation: -1});
      
      db.adminCommand({
        analyzeShardKey: "sample_supplies.sales",
        key: {purchaseMethod: 1},
        keyCharacteristics: true,
        readWriteDistribution: true,
        sampleSize: 1000000
      });
      

      The same failure occurs for {purchaseMethod: 1, saleDate: 1} — any prefix of the descending index.

      Analysis

      findCompatiblePrefixedIndex selects the supporting index using shardKey.isFieldNamePrefixOf(indexKey), which matches on field names and ignores direction. It skips indexes that are multikey, sparse, partial, or have a non-simple collation, but has no skip condition for direction.

      The selected index is then passed to validateIndexKey(hintIndexKey) in makeAggregateRequestForCardinalityAndFrequency, which routes to validateShardKeyPattern and uasserts that every non-hashed field equals 1. The descending field fails that check and the whole command aborts.

      So the command picks an index it is about to reject, rather than skipping it and continuing the search.

      Code references (master, 18be87d5b5a63583bc574a0d5234d3316f5243cf):

      • Index selection: src/mongo/db/s/analyze_shard_key_cmd_util.cpp, findCompatiblePrefixedIndex (prefix match at L458, skip conditions at L444-456)
      • Rejection: same file, validateIndexKey(hintIndexKey) at L193
      • uassert: src/mongo/db/global_catalog/shard_key_pattern.cpp L87

      Expected behaviour

      Direction should be one more skip condition in the selection loop, alongside multikey/sparse/partial/collation. The command would then fall through to the next compatible index, or to the documented "no supporting index" path (IllegalOperation), instead of failing with a parse error about a pattern the caller did not supply.

      Note that index direction is irrelevant to the metrics being computed. A descending index contains the same key values as its ascending counterpart, just in reverse order — cardinality, distinct value counts and most-common-values do not depend on it.

      Documentation

      The analyzeShardKey reference page enumerates the disqualifying index properties — simple collation, not multi-key, not sparse, not partial — which match the code's four skip conditions exactly. Direction appears in neither list.

      The same page states the command is deliberately more permissive about supporting indexes than shardCollection, "to allow you to analyze a shard key that may not yet have a supporting index required for sharding it". Applying shardCollection's all-ascending shard key rule to index selection inverts that intent. The docs also describe IllegalOperation as the error for a missing supporting index; BadValue for this condition is undocumented.

      Impact

      This affects MongoDB Atlas's Sharding Advisor, which calls analyzeShardKey to evaluate candidate shard keys. Atlas currently sidesteps the failure in its UI by excluding any index containing a descending field from the shard key candidate dropdown, so today it surfaces only on manually entered keys.

      That mitigation does not extend to the recommendation engine. Recommendations are derived from workload analysis rather than from the filtered index list, so a recommended key is judged on how well it targets the workload — not on which unrelated indexes happen to exist on the collection. Any recommendation whose fields prefix-match a descending index will fail analysis. Descending compound indexes are common in real collections, making this a material source of otherwise unexplained failures once recommendations drive analysis at scale.

      Workaround

      Resubmitting with keyCharacteristics: false, readWriteDistribution: true succeeds, since the index selection runs only inside the key-characteristics branch. That returns the read/write distribution metrics but no cardinality, monotonicity or most-common-values data.

      Alternatively, creating an ascending index on exactly the candidate key displaces the descending one, because the selection loop prefers the index with fewer fields — though a unique descending index still wins, as unique is preferred over field count.

            Assignee:
            Unassigned
            Reporter:
            Alex Dambrouski
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: