Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CastError doesn't return the entire nested path #14114

Closed
1 task done
mlort1 opened this issue Nov 23, 2023 · 4 comments · Fixed by #14161
Closed
1 task done

CastError doesn't return the entire nested path #14114

mlort1 opened this issue Nov 23, 2023 · 4 comments · Fixed by #14161
Assignees
Milestone

Comments

@mlort1
Copy link

mlort1 commented Nov 23, 2023

Prerequisites

  • I have written a descriptive issue title

Mongoose version

8.0.0

Node.js version

20.9.0

MongoDB version

6.2.0

Operating system

None

Operating system version (i.e. 20.04, 11.3, 10)

No response

Issue

Hello,
I'm testing Mongoose error feedback. When testing a ValidationError, the response returns a nested path, which allows me to trace the field in error in my object that I passed in my query.
Example: 'accessories.0.additionals.0.k'.
It's very useful for browsing and finding fields in error.

However, when testing a CastError, the return sends me the error by browsing the object. This means I can't go back down into my object to find my error correctly.
Example: for arrays, the index isn't specified, so it's impossible to retrieve it.

Schema :

{
    id: Schema.Types.ObjectId,
    name: String,
    accessories: [
        {
            isEnabled: Boolean,
            additionals: [
                {
                    k: String,
                    v: Number,
                },
            ],
        }
    ],
    actions: [
        {
            type: String,
            isEnabled: Boolean,
            subActions: [
                {
                    type: String,
                    isEnabled: Boolean,
                }
            ],
        },
    ],
}

Example of a body sent :

{
    "id": "6499a3ff77eb47522397bbc1",
    "name": "Soldier",
    "accessories": [
        {
            "isEnabled": true,
            "additionals": [
                {
                    "k": ["helmet"], 	        // mock an error type here
                    "v": 1,
                },
                {
                    "k": "shoes",
                    "v": 2,
                },
            ],
        }
    ],
    "actions": [
        {
            "type": "move",
            "isEnabled": true,
            "subActions": [
                {
                    "type": "move right",
                    "isEnabled": true,
                }
            ],
        },
    ],
}

And the server returns this CastError :

CastError: Cast to embedded failed for value "{
   isEnabled: true,
   additionals: [
     { k: [Array], v: 1 },
     { k: 'shoes', v: 50 },
   ],
   _id: '654d005f44b6b34ae2e19c43'
 }" (type Object) at path "accessories" because of "CastError" {
     stringValue: '"{\n' +
       "  isEnabled: true,\n" +
       '  additionals: [\n' +
       "    { k: [Array], v: 1 },\n" +
       "    { k: 'shoes', v: 2 },\n" +
       '  ],\n' +
       "  _id: '654d005f44b6b34ae2e19c43'\n" +
       '}"',
   messageFormat: undefined,
   kind: 'embedded',
   value: {
       isEnabled: true,
       additionals: [ [Object], [Object] ],
       _id: '654d005f44b6b34ae2e19c43'
   },
   path: 'accessories', 
   reason: CastError: Cast to embedded failed for value "{
         k: [ 'helmet' ],
         v: 1,
         _id: '654d005f44b6b34ae2e19c44'
     }" (type Object) at path "additionals" because of "CastError" {
         stringValue: '"{\n' +
           "  k: [ 'helmet' ],\n" +
           "  v: 1,\n" +
           "  _id: '654d005f44b6b34ae2e19c44'\n" +
           '}"',
       messageFormat: undefined,
       kind: 'embedded',
       value: { k: [Array], v: [Object], _id: '654d005f44b6b34ae2e19c44' },
       path: 'additionals',
       reason: CastError: Cast to string failed for value "[ 'helmet' ]" (type Array) at path "k" {
            stringValue: `"[ 'helmet' ]"`,
            messageFormat: undefined,
            kind: 'string',
            value: [Array],
            path: 'k', 
            reason: null,
            valueType: 'Array'
          },
       valueType: 'Object'
     },
   valueType: 'Object'
 }

Example of a ValidationError :

ValidationError : 
Error: Validation failed: accessories.0.additionals.0.k: "helme" doesn't belong to the defined values. {
   errors: {
     'accessories.0.additionals.0.k': ValidatorError: "helme" doesn't belong to the defined values.) {
       properties: [Object],
       kind: 'enum',
       path: 'accessories.0.additionals.0.k',                         // expected path for CastError
       value: 'helme',
       reason: undefined,
       [Symbol(mongoose:validatorError)]: true
     }
   },
   _message: 'Validation failed'
 }
@mlort1 mlort1 added help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary help wanted labels Nov 23, 2023
@vkarpov15 vkarpov15 added this to the 8.0.2 milestone Nov 25, 2023
@vkarpov15 vkarpov15 added has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue and removed help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary help wanted labels Nov 25, 2023
@IslandRhythms IslandRhythms added can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. and removed has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels Nov 27, 2023
@IslandRhythms
Copy link
Collaborator

Am able to get pathing for the errors. Please modify script below to demonstrate your issue.

const mongoose = require('mongoose');

const testSchema = new mongoose.Schema({
  id: mongoose.Schema.Types.ObjectId,
  name: String,
  accessories: [
      {
          isEnabled: Boolean,
          additionals: [
              {
                  k: String,
                  v: Number,
              },
          ],
      }
  ],
  actions: [
      {
          type: String,
          isEnabled: Boolean,
          subActions: [
              {
                  type: String,
                  isEnabled: Boolean,
              }
          ],
      },
  ],
});

const Test = mongoose.model('Test', testSchema);

async function run() {
  await mongoose.connect('mongodb://localhost:27017');
  await mongoose.connection.dropDatabase();

  const obj = {
    // id: '123456789012',
    name: 'Soldier',
    accessories: [
      {
        isEnabled: true,
        additionals: [
          {
            k: ['helmet'],
            v: 1
          },
          {
            k: 'shoes',
            v: 2
          }
        ]
      }
    ],
    actions: [
      {
        type: 'move',
        isEnabled: true,
        subActions: [
          { type: 'move right',
            isEnabled: true
          }
        ]
      }
    ]
  }

  await Test.create(obj);
  console.log(await Test.findOne())
  console.log('done');
}

run();

@rommni
Copy link

rommni commented Nov 28, 2023

Hello thanks to have experimented, the problem seems to only appear on CastError and I can't manage to produce a CastError on create, we only have ValidationError.
On update however I manage to get the CastError with incomplete path. You should see the error updating you code as following:

const mongoose = require('mongoose');

const testSchema = new mongoose.Schema({
  id: mongoose.Schema.Types.ObjectId,
  name: String,
  accessories: [
      {
          isEnabled: Boolean,
          additionals: [
              {
                  k: String,
                  v: Number,
              },
          ],
      }
  ],
  actions: [
      {
          type: {type:String },
          isEnabled: Boolean,
          subActions: [
              {
                  type: {type:String },
                  isEnabled: Boolean,
              }
          ],
      },
  ],
});

const Test = mongoose.model('Test', testSchema);

async function run() {
  await mongoose.connect('mongodb://localhost:27017');
  await mongoose.connection.dropDatabase();

  const obj = {
    // id: '123456789012',
    name: 'Soldier',
    accessories: [
      {
        isEnabled: true,
        additionals: [
          {
            k: 'test',
            v: 1
          },
          {
            k: 'shoes',
            v: 2
          }
        ]
      }
    ],
    actions: [
      {
        type: 'move',
        isEnabled: true,
        subActions: [
          { type: 'move right',
            isEnabled: true
          }
        ]
      }
    ]
  }

  let soldier = await Test.create(obj);
  await Test.findOneAndUpdate({_id : soldier._id}, {
    "$set": {
      "accessories.0.additionals.0.k": ['test']
    }
  })

  console.log('done');
}

run();

@vkarpov15 vkarpov15 added has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue and removed can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. labels Nov 28, 2023
@vkarpov15 vkarpov15 modified the milestones: 8.0.2, 8.0.3 Nov 28, 2023
@IslandRhythms IslandRhythms added can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. and removed has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels Nov 29, 2023
@IslandRhythms
Copy link
Collaborator

Not able to reproduce but from the error message you had copy-pasted it seems like an object was passed and that triggered the cast error as opposed to the array of strings.
Although reason is null in this cast error so that may be an issue.

CastError: Cast to string failed for value "[ 'test' ]" (type Array) at path "k"
    at SchemaString.cast (C:\Users\Drumm\Desktop\Work\debugging\JavaScript\node_modules\mongoose\lib\schema\string.js:606:11)
    at SchemaString.SchemaType.applySetters (C:\Users\Drumm\Desktop\Work\debugging\JavaScript\node_modules\mongoose\lib\schemaType.js:1219:12)
    at SchemaString.castForQuery (C:\Users\Drumm\Desktop\Work\debugging\JavaScript\node_modules\mongoose\lib\schema\string.js:690:15)
    at castUpdateVal (C:\Users\Drumm\Desktop\Work\debugging\JavaScript\node_modules\mongoose\lib\helpers\query\castUpdate.js:569:19)
    at walkUpdatePath (C:\Users\Drumm\Desktop\Work\debugging\JavaScript\node_modules\mongoose\lib\helpers\query\castUpdate.js:374:24)
    at castUpdate (C:\Users\Drumm\Desktop\Work\debugging\JavaScript\node_modules\mongoose\lib\helpers\query\castUpdate.js:107:7)
    at model.Query._castUpdate (C:\Users\Drumm\Desktop\Work\debugging\JavaScript\node_modules\mongoose\lib\query.js:4569:10)
    at model.Query._findOneAndUpdate (C:\Users\Drumm\Desktop\Work\debugging\JavaScript\node_modules\mongoose\lib\query.js:3260:23)
    at model.Query.exec (C:\Users\Drumm\Desktop\Work\debugging\JavaScript\node_modules\mongoose\lib\query.js:4290:80)
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  stringValue: `"[ 'test' ]"`,
  messageFormat: undefined,
  kind: 'string',
  value: [ 'test' ],
  path: 'k',
  reason: null,
  valueType: 'Array'
}

@rommni
Copy link

rommni commented Nov 30, 2023

Hello, thank you for your time.
I'm not sure to understand your asnwer, sorry. If the message you pasted is the error message you got, you have the problem we mentionned.
You can see that path value in your message is "k", while I think we want something like ValidationError which was something like "accessories.0.additionals.0.k"

@vkarpov15 vkarpov15 removed the can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. label Dec 4, 2023
@vkarpov15 vkarpov15 modified the milestones: 8.0.3, 8.0.4 Dec 7, 2023
vkarpov15 added a commit that referenced this issue Dec 24, 2023
fix(update): set CastError path to full path if casting update fails
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants