typeorm icon indicating copy to clipboard operation
typeorm copied to clipboard

Postgres TypeError: Converting circular structure to JSON

Open theoparis opened this issue 5 years ago • 7 comments

Issue Description

So I am using postgresql with typeorm and nestjs and I have a user entity. When I run .findOne({username }) it works fine, but doing .find({}) to get all simply gives this error:

TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Socket'
    |     property 'parser' -> object with constructor 'HTTPParser'       
    --- property 'socket' closes the circle
    at JSON.stringify (<anonymous>)
    at SelectQueryBuilder.<anonymous> (C:\Users\thebo\Documents\ProxyByrd\packages\backend\node_modules\.pnpm\[email protected]\node_modules\typeorm\query-builder\SelectQueryBuilder.js:1553:67)

Expected Behavior

The following code should return the list of users to the backend:

    async findAll(): Promise<User[]> {
        return await this.usersRepository.find({ take: 5 });
    }

Actual Behavior

It errors with circular socket structure error:

TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Socket'
    |     property 'parser' -> object with constructor 'HTTPParser'       
    --- property 'socket' closes the circle
    at JSON.stringify (<anonymous>)
    at SelectQueryBuilder.<anonymous> (C:\Users\thebo\Documents\ProxyByrd\packages\backend\node_modules\.pnpm\[email protected]\node_modules\typeorm\query-builder\SelectQueryBuilder.js:1553:67)

Steps to Reproduce

  1. Use nestjs and typeorm
  2. Try to call .find({}) on an injected repository in a service.

My Environment

Dependency Version
Operating System Windows 10
Node.js version 14.0.0
Typescript version 4.0.5
TypeORM version 0.2.28

Relevant Database Driver(s)

  • [ ] aurora-data-api
  • [ ] aurora-data-api-pg
  • [ ] better-sqlite3
  • [ ] cockroachdb
  • [ ] cordova
  • [ ] expo
  • [ ] mongodb
  • [ ] mysql
  • [ ] nativescript
  • [ ] oracle
  • [x ] postgres
  • [ ] react-native
  • [ ] sap
  • [ ] sqlite
  • [ ] sqlite-abstract
  • [ ] sqljs
  • [ ] sqlserver

Are you willing to resolve this issue by submitting a Pull Request?

  • [ ] Yes, I have the time, and I know how to start.
  • [x] Yes, I have the time, but I don't know how to start. I would need guidance.
  • [ ] No, I don't have the time, although I believe I could do it if I had the time...
  • [ ] No, I don't have the time and I wouldn't even know how to start.

theoparis avatar Nov 01 '20 20:11 theoparis

Can you create a repository that exhibits this? I can't replicate it with TypeORM natively.

imnotjames avatar Nov 01 '20 23:11 imnotjames

Sure, I have pushed the monorepo that I have to github (development branch) You should be able to use the packages/backend folder directly without using the monorepo with pnpm.

Maybe it is a nestjs/typeorm issue and not just typeorm but I'm unable to to figure out the code that would be causing a problem other than typeorm itself.

Also, I've never really had this issue before so I am not sure how else I can reproduce it.

theoparis avatar Nov 02 '20 21:11 theoparis

We have the same problem. It occurs when we call manager.save(partyEntity).

This is how our entities look like:

@Unique("UK_uid", ["uid"])
@Entity("party")
export class PartyEntity {

    constructor(id: string, type: PartyType, uid: string) {
        this.id = id
        this.type = type
        this.uid = uid
    }

    @PrimaryGeneratedColumn('uuid')
    id: string

    @Column({
        type: "enum",
        enum: PartyType
    })
    type: PartyType

    @Column()
    uid: string

    @OneToMany(() => PartyContactEntity, partyContact => partyContact.party, {cascade: true})
    contacts: PartyContactEntity[]
}
@Entity("customer_contact")
export class PartyContactEntity {

    constructor(party: PartyEntity, contactMedium: ContactMediumEntity) {
        this.party = party;
        this.contactMedium = contactMedium;
    }

    @PrimaryColumn('uuid', {name: "party_id"})
    @ManyToOne(() => PartyEntity, party => party.contacts)
    party: PartyEntity

    @PrimaryColumn('uuid', {name: "contact_id"})
    @OneToOne(() => ContactMediumEntity)
    @JoinColumn({name: "contact_id", referencedColumnName: "id"})
    contactMedium: ContactMediumEntity

}

Is there an error in how we've built our entities?

ghost avatar Nov 17 '20 13:11 ghost

It happens in TypeORM 0.2.22 and 0.2.18 as well. I guess, there is some modelling error on my side?

ghost avatar Nov 17 '20 13:11 ghost

@ErolPeel When saving a One-to-Many relation in TypeORM you need to be careful to only reference one side of the relation. For example when you want to save a PartyEntity with a PartyContactEntity, do it like this:

const partyContactEntity: PartyContactEntity = new PartyContactEntity()
partyContactEntity.contactMedium = savedPostalContactEntity.contactMedium
// important: do not set the partyContactEntity.party here as this will result in the 
// "TypeError: Converting circular structure to JSON" error when saving the contact with the party

const partyEntity: PartyEntity = new PartyEntity( ... )
partyEntity.contacts = [partyContactEntity]

manager.save(partyEntity)

Cleatuer avatar Nov 18 '20 11:11 Cleatuer

Hi got the same error message but on a different context (using createQueryBuilder) I resolved this by adding either : .getOne() .getRawOne() .getMany() .getRawMany() Hope that can be useful

Miodav avatar Aug 25 '22 10:08 Miodav

You most likely have a reverse relationship between 2 of your tables involved in the query. You have to avoid referencing the parent table in the child table. E.g You need to prevent something like this: Parent-> Child -> Parent. I had to delete a parent reference within a child table.

image

gaffarmalik avatar May 05 '24 12:05 gaffarmalik