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

firstOrCreate() causes infinite loop in beforeUpdate() hook #1021

Open
FrenchMajesty opened this issue Mar 27, 2024 · 0 comments
Open

firstOrCreate() causes infinite loop in beforeUpdate() hook #1021

FrenchMajesty opened this issue Mar 27, 2024 · 0 comments

Comments

@FrenchMajesty
Copy link

FrenchMajesty commented Mar 27, 2024

Package version

18.4.2

Describe the bug

I have noticed that trying to create a related model from an update hook causes an infinite loop which blows up the stack.

See the following code:

class User extends Model {
  @hasOne(() => PromoterOnboarding)
  public promoter: HasOne<typeof PromoterOnboarding>

  @beforeUpdate()
  public static async beforeUpdateHook(user: User) {
    if (user.$dirty.billingPlan === 'promoter') {
      console.log(user.$dirty)
      await user.related('promoter').query().firstOrCreate({ id: user.id })
    }
  }
}

When attempting to update the user via the following code:

    await user
      .merge({
        stripeCustomerId: customer.id,
        billingPlan: 'promoter',
        onboardedAt: DateTime.now(),
      })
      .save()

The server crashes out with the following error:

{
"message": "Maximum call stack size exceeded",
"stack": "RangeError: Maximum call stack size exceeded\n at formatRaw (node:internal/util/inspect:1060:50)\n at formatValue (node:internal/util/inspect:839:10)\n at inspect (node:internal/util/inspect:363:10)\n at formatWithOptionsInternal (node:internal/util/inspect:2297:40)\n at formatWithOptions (node:internal/util/inspect:2159:10)\n at console.value (node:internal/console/constructor:342:14)\n at console.log (node:internal/console/constructor:379:61)\n at Function.beforeUpdateHook (/my-app-source/Models/User.ts:271:15)\n at Hooks.exec (/my-app-source/node_modules/@adonisjs/lucid/node_modules/@poppinss/hooks/build/src/Hooks/index.js:129:23)\n at Proxy.save (/my-app-source/node_modules/@adonisjs/lucid/build/src/Orm/BaseModel/index.js:1379:28)"
}

I can observe that this beforeUpdate() hook is getting called recursively non-stop unless I kill the server. See screenshot:

Screenshot 2024-03-26 at 7 57 28 PM

Interestingly, the following snippet does not fail:

if (user.$dirty.billingPlan === 'promoter') {
      const exists = await user.related('promoter').query().first()
      if (!exists) {
        await user.related('promoter').create({ id: user.id })
      }
    }

It seems to be an issue with the firstOrCreate() method.

Will put together a repro repo if I have time

Reproduction repo

No response

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

No branches or pull requests

1 participant