typeorm: TypeError: Cannot convert object to primitive value

Issue type:

[ ] question [x] bug report [ ] feature request [ ] documentation issue

Database system/driver:

[ ] cordova [ ] mongodb [ ] mssql [ ] mysql / mariadb [ ] oracle [x] postgres [ ] sqlite [ ] sqljs [ ] react-native

TypeORM version:

[ ] latest [ ] @next [x] 0.2.0 (or put your version here)

Steps to reproduce or a small repository showing the problem:

I am using NestJs with Typeorm I get the request object form graphql, graphql parameters do not have __proto__ set. I am directly passing the graphql paramter object to the save method. I am getting the below error when I do that:

TypeError: Cannot convert object to primitive value
    at new MustBeEntityError (/Users/shashikiranms/projects/vcbackend/src/error/MustBeEntityError.ts:10:43)
    at EntityPersistExecutor.execute (/Users/shashikiranms/projects/vcbackend/node_modules/typeorm/persistence/EntityPersistExecutor.js:77:35)
    at EntityManager.save (/Users/shashikiranms/projects/vcbackend/src/entity-manager/EntityManager.ts:298:14)
    at UserRepository.Repository.save (/Users/shashikiranms/projects/vcbackend/src/repository/Repository.ts:138:29)

When I debugged the issue, it is beacause EntityPersistExecutor.js checks for the entity to be an instanceof Object, which is false, because __proto__ is not set for the entity

if (!this.entity || !(this.entity instanceof Object)) {
     return Promise.reject(new MustBeEntityError_1.MustBeEntityError(this.mode, this.entity));
}

I think changing the above condition this.entity instanceof Object to typeof this.entity === 'object' solves the problem

PS: It was working in version 0.1.20. It is breaking once I upgraded to 0.2.0

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 19 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Just ran into this issue using type-graphql, typeorm and nestjs and was scratching my head for a while. This is a really obtuse issue and causes silent bugs. There are workarounds but it really needs to be fixed.

I solved it for my use case in NestJS with a simple object spread (required for input):

@Mutation(() => Item)               
public createItem(@Args('input') input: ItemCreateInput): Promise<Item>         
  return this.itemsService.create({...input}) // spread operator to clone input to new object                            
 } 

Hope it helps…

Any news on that?

Many other projects are trying to create Objects by Object.create(null), which results in [Object: null prototype].

However, there are so many instanceof Object in typeorm, which may cause a lot of issues.

Object.create(null) instanceof Object // false

Hope we can fix that, or at least put a notice in the documentation.

this.entity is not null but an object, but it does not inherit from Object (i.e this.entity.__proto__ is undefined) that’s why this.entity instanceof Object is false.

The request object I get from graphQL is being created by Object.create(null);, hence instanceof Object is false in my case

Please refer to the conversation in the below pull request, where they are using Object.create(null) to create an object: https://github.com/graphql/graphql-js/pull/504

I use NestJS (GraphQL) and TypeORM. To bypass the issue I created a global pipe as shown bellow:

import { PipeTransform } from '@nestjs/common/interfaces';

class EnsurePrototypePipe implements PipeTransform {
  transform(argument: unknown) {
    return ensurePrototype(argument);
  }
}

const ensurePrototype = (input: unknown): unknown => {
  if (Array.isArray(input)) {
    return input.map(it => ensurePrototype(it));
  }
  if (isObjectLiteral(input) && input.prototype === undefined) {
    const output = {};
    Object.keys(input).forEach(property => {
      output[property] = ensurePrototype(input[property]);
    });
    return output;
  }
  return input;
};

export const isObjectLiteral = (v: unknown): v is Record<string | number | symbol, unknown> => {
  if (typeof v !== 'object' || v == null) {
    return false;
  }
  const constructor = v.constructor;
  return constructor === undefined || constructor === Object;
};

And apply this pipe globally:

<...>
nestApp.useGlobalPipes(new EnsurePrototypePipe())
<...>