New smart relationship causes CastError on different attribute in collection

Summary

When adding a new smart relationship, the relationship is added successfully in the collection table view but when clicking into a collection item’s summary/detail view an error is thrown on the Admin Backend:

[forest] 🌳🌳🌳  Unexpected error: Cast to ObjectId failed for value "{
  country: 'US',
  street: 'fake',
  complement: '',
  state: 'fake',
  city: 'fake',
  zipCode: 'fake'
}" (type Object) at path "_id" for model "Company"

Feature(s) impacted

  • Smart relationships
  • Viewing collection item summary/details

Observed behavior

A smart relationship:

{
      field: 'balance account',
      type: 'String',
      reference: 'CompanyAccount._id',
      get: async company => {
        const accounts = await companyAccountModel.aggregate([
          {
            $lookup: {
              from: 'users',
              localField: 'companyId',
              foreignField: '_id',
              as: 'user_doc',
            },
          },
          {
            $match: {
              'user_doc._id': company._id,
            },
          },
        ]);
        return accounts?.[0]?._id;
      },
    },

on a collection named “Companies” results in a successful linking to the “CompanyAccount” collection in the collection table view (when it exists):

but when I click on an item in this collection to view it’s summary/detail view, I get an error:


(see the failure logs section for the stack trace)

This only occurs for “Companies” that have an “account” attribute. For “Companies” that haven’t gone through the onboarding process, there is no “account” attribute and the summary/details view displays without error.

Expected behavior

I would expect to be able to click into a “Companies” collection item to view its summary/details view. The smart relationship field “balance account” should be available in the summary/details view.

Failure Logs

Stack trace:

[forest] 🌳🌳🌳  Unexpected error: Cast to ObjectId failed for value "{
  country: 'US',
  street: 'fake',
  complement: '',
  state: 'fake',
  city: 'fake',
  zipCode: 'fake'
}" (type Object) at path "_id" for model "Company"
{
  "stringValue": "\"{\n  country: 'US',\n  street: 'fake',\n  complement: '',\n  state: 'fake',\n  city: 'fake',\n  zipCode: 'fake'\n}\"",
  "kind": "ObjectId",
  "value": {
    "country": "US",
    "street": "fake",
    "complement": "",
    "state": "fake",
    "city": "fake",
    "zipCode": "fake"
  },
  "path": "_id",
  "reason": {},
  "valueType": "Object",
  "stack": "CastError: Cast to ObjectId failed for value \"{\n  country: 'US',\n  street: 'fake',\n  complement: '',\n  state: 'fake',\n  city: 'fake',\n  zipCode: 'fake'\n}\" (type Object) at path \"_id\" for model \"Company\"\n 

Context

  • Project name: subscribe.so
  • Team name: Operations
  • Environment name: DEVELOPMENT | SUBSCRIBEADMIN (FEATURE/SUB-13)
  • Agent type & version: forest-express-mongoose@^8.7.0

Recent changes made:

  • Added a smart relationship to the “Companies” collection (see the Observed Behavior section) - this error does not occur when this smart relationship is removed

FYI on the “Companies” collection:
The “Companies” collection inherits it’s schema from the “Users” collection via discriminators so a company is a user with a userType attribute of “company” (userType is the discriminatorKey).

Companies have an “account” attribute that has multiple levels of nested schemas:

const addressSchema: Schema = new Schema(
  {
    street: {
      type: String,
    },
    complement: {
      type: String,
    },
    city: {
      type: String,
    },
    state: {
      type: String,
    },
    zipCode: {
      type: String,
    },
    country: {
      type: String,
      default: 'US',
    },
  },
  { _id: false, id: false },
);

const companyOwnerSchema: Schema = new Schema(
  {
    name: {
      type: String,
    },
    title: {
      type: String,
    },
    phone: {
      type: String,
    },
    email: {
      type: String,
    },
  },
  { _id: false, id: false },
);

const accountCompanySchema: Schema = new Schema(
  {
    legalName: {
      type: String,
    },
    corporationType: {
      type: String,
    },
    stateOfIncorporation: {
      type: String,
    },
    owner: companyOwnerSchema,
    address: addressSchema,
  },
  { _id: false, id: false },
);

const companySchema: Schema = new Schema(
  {
    account: {
      type: accountCompanySchema,
    },
    invoiceSettings: invoiceSettingsSchema,
  },
  { _id: false },
);

// userModel not included here for brevity
const companyModel = userModel.discriminator<Company & Document>('Company', companySchema, PermissionEnum.company);

Ideas

The cast error makes it seem like something is trying to use company.account.address as the input to an ObjectId() call. I’m wondering if there is some unexpected naming conflict that Forest is running into with that account attribute? The naming of CompanyAccount and balance account are obviously similar but not exactly the same so this is really stumping me.

Thanks for any help.

Hey @kellen :wave:,

I can see that you address model has both _id and id disabled.
Without the smart relation, are you able to list all your adresses ?

Not having any kind of value that could be used as a primary key could definitely be an issue here.
Also, could you provide the frontend stacktrace so I can investigate on my end?

Thanks in advance

Thanks for the quick reply.

This is a project I’m taking over so I’m not sure why both _id and id are disabled on the address schema but that’s just a nested schema in the users model. Addresses are not in their own collection. So not able to list all our addresses and not trying to at this time. Just trying to set up the relationship between a Company and a CompanyAccount.

I did try removing { _id: false, id: false }, from the addressSchema and I still get the same error but I’m not sure if that would generate those attributes for existing documents in the collection?

Here is the frontend stacktrace:

{
    "isAdapterError": true,
    "stack": "Error: Ember Data Request GET http://localhost:3001/forest/Company/62bf5a9c38924ddda2ea7053 returned a 500\nPayload (application/json; charset=utf-8)\n[object Object]\n    at n.i (https://app.forestadmin.com/assets/vendor-ba6d5c5904c15046f5f2be0771c35dc5.js:139:229557)\n    at new n (https://app.forestadmin.com/assets/vendor-ba6d5c5904c15046f5f2be0771c35dc5.js:139:230315)\n    at b.handleResponse (https://app.forestadmin.com/assets/vendor-ba6d5c5904c15046f5f2be0771c35dc5.js:139:236787)\n    at b.handleResponse (https://app.forestadmin.com/assets/client-0de6629c142e1830ef2b44a6ec4808a2.js:1:4114396)\n    at A (https://app.forestadmin.com/assets/vendor-ba6d5c5904c15046f5f2be0771c35dc5.js:139:241041)\n    at https://app.forestadmin.com/assets/vendor-ba6d5c5904c15046f5f2be0771c35dc5.js:139:237719\n    at a.Promise.u.error (https://app.forestadmin.com/assets/vendor-ba6d5c5904c15046f5f2be0771c35dc5.js:139:237730)\n    at l (https://app.forestadmin.com/assets/vendor-ba6d5c5904c15046f5f2be0771c35dc5.js:48:24786)\n    at Object.fireWith [as rejectWith] (https://app.forestadmin.com/assets/vendor-ba6d5c5904c15046f5f2be0771c35dc5.js:48:25534)\n    at S (https://app.forestadmin.com/assets/vendor-ba6d5c5904c15046f5f2be0771c35dc5.js:48:76509)\n    at XMLHttpRequest.<anonymous> (https://app.forestadmin.com/assets/vendor-ba6d5c5904c15046f5f2be0771c35dc5.js:48:78952)\n    at XMLHttpRequest.i (https://app.forestadmin.com/assets/chunk.68.a053053744394054b79f.js:1:49166)",
    "message": "Ember Data Request GET http://localhost:3001/forest/Company/62bf5a9c38924ddda2ea7053 returned a 500\nPayload (application/json; charset=utf-8)\n[object Object]",
    "name": "Error",
    "errors": [
        {
            "status": 500,
            "detail": "Cast to ObjectId failed for value \"{\n  country: 'US',\n  street: 'fake',\n  complement: '',\n  state: 'fake',\n  city: 'fake',\n  zipCode: 'fake'\n}\" (type Object) at path \"_id\" for model \"Company\"",
            "name": "CastError"
        }
    ]
}

Is /forest/Company/:id an autogenerated route? I don’t have that route defined explicitly in my codebase.

Yes sorry, that’s most likely not the issue here (But as the error appeared to be a cast of address as an ObjectId, I thought it may help). My thinking was more about the fact that for a forest collection to work, an unique id/primary key is required.

/forest/Company/:id should be autogenerated indeed. Could you also share the request URL and payload that is failing?

On my end, I’ll take a look on our backoffice to see if I can spot anything.

For sure:


Request url (so you can copy/paste): http://localhost:3001/forest/Company/62bf5a9c38924ddda2ea7053?timezone=America%2FNew_York

Still not super sure of what is happening.

However, it seems like your Company model, in the .forestadmin-schema.json, is using _id as a primary key. However, in your schema, you have { _id: false }, so I’m pretty sure this could be the issue here. I’m still not sure why “address” would be considered as something to cast to ObjectId by default though.

If you do have _id on the Company model, I would suggest to remove this { _id: false } and check if the issue is still happening (As well as re-add the { _id: false, id: false }, from the addressSchema).

If it still does not work, I’ll setup a project similar to your to see if I’m able to reproduce the issue.

I removed { _id: false } from companySchema and still got the same error.

With that removed I tried with { _id: false, id: false } on the addressSchema and without and got the same error for both cases.

This is pretty bizarre, I also can’t think of why something would be accessing the account.address attribute. That cast error makes it seem like something is trying to perform a query where account.address is being referenced as an _id so mongoose casts it to ObjectId but obviously it’s not a valid ObjectId.

Do you have any other ideas for possible causes or suggestions for debugging approaches?

Hey @kellen (I was off the last few days)

With the setup were you removed { _id: false } from companySchema and with { _id: false, id: false } on the addressSchema re-added, are you still experiencing the exact same error?

Could you also include the response body (The error received on the frontend) in the request you shared earlier?

Thanks in advance

Hey @jeffladiray, all good! I figured.

Yes, I got the exact same error with those modifications. But I actually found a solution just now.

I found the only reference to a forest-express-mongoose file in the stacktrace and added some breakpoints in there to see if anything jumped out at me as seemingly wrong.

I ended up on this line: forest-express-mongoose/resource-getter.js at 3dce482785ee208106ff99ae8c90311632e19838 · ForestAdmin/forest-express-mongoose · GitHub and realized that this code is performing a mongoose .populate using the the smart field’s field attribute (which I had set to “balance account”). I thought: well maybe that’s resulting in a reference to the account attribute of the companySchema somehow…

I changed the name of my smart relationship (i.e. smart field) to “balance_account” (note the underscore) and no longer received the error and was able to visit the summary/detail view of the company.

So that resolves my issue but this seems like very odd behavior to me still and is most likely a bug you’ll want to play around with on your end? My immediate problem is solved for now though.

Thanks for your help on this.

Thanks for letting me know. I’ll mark the thread as solved as your main issue seems to be solved for now.

I’ll perform a few tests with a datastructure similar to yours and let you know either if I’m able to reproduce, or if I can spot anything interesting.

Thanks again :pray:

1 Like