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

Maximum call stack size exceeded #1

Closed
TheBumpaster opened this issue Aug 6, 2023 · 1 comment
Closed

Maximum call stack size exceeded #1

TheBumpaster opened this issue Aug 6, 2023 · 1 comment

Comments

@TheBumpaster
Copy link

In reference to my old issue: giddyinc#64

The "Maximum call stack size exceeded" error usually indicates that there is a recursive loop running indefinitely. Given your Mongoose schema setup and the provided conversion code, it's highly likely that the infinite recursion is happening because of how the code handles nested schemas or references.

Let's try a step-by-step approach to debug and solve this:

  1. Detect and Prevent Infinite Recursion: We can introduce a depth check or a recursive-path check to stop the recursion after a certain depth or if the function comes across the same path more than once.

  2. Refactor the Recursive Calls: It's essential to handle the base cases and recursion properly to prevent such errors. If there is a cyclic reference in the Mongoose schema or any unintended recursive path, this will ensure it's caught.

Let's begin by adding a depth check:

Step 1: Add a depth check

To prevent infinite recursion, we'll add a depth parameter to the recursive functions and increase it with each recursive call. If the depth surpasses a certain threshold, we'll stop the recursion.

const MAX_DEPTH = 10;

const mapSchemaTypeToFieldSchema = ({ key = null, value, props, omitFields, depth = 0 }) => {
    if (depth > MAX_DEPTH) {
        throw new Error(`Max recursion depth of ${MAX_DEPTH} exceeded`);
    }
    // ... rest of the function ...

    if (swaggerType === 'array') {
        // ... other parts of the code ...
        const items = mapSchemaTypeToFieldSchema({ value: arraySchema || {}, props, omitFields, depth: depth + 1 });
        meta.items = items;
    }
    // ... rest of the function ...
};

const getFieldsFromMongooseSchema = (schema, options, depth = 0) => {
    if (depth > MAX_DEPTH) {
        throw new Error(`Max recursion depth of ${MAX_DEPTH} exceeded`);
    }
    // ... rest of the function ...
};

Step 2: Track recursive paths

Besides depth, another way to detect recursion is by tracking which paths you've visited. If a path is revisited, that means there's a cycle.

To achieve this, you can use an array or a set to track the paths that your function has visited:

const mapSchemaTypeToFieldSchema = ({ key = null, value, props, omitFields, depth = 0, visitedPaths = [] }) => {
    if (visitedPaths.includes(key)) {
        return { type: 'object' }; // or any default value to break the cycle
    }
    visitedPaths.push(key);
    // ... rest of the function ...
};

const getFieldsFromMongooseSchema = (schema, options, depth = 0, visitedPaths = []) => {
    // ... rest of the function ...
};

These changes should help detect and prevent infinite recursion. You may need to tweak the depth or adjust how you handle cyclic references based on your specific use case.

After implementing these changes, run your code. If it throws the "Max recursion depth exceeded" error, then you can be sure that the recursion depth is the issue. If it doesn't, but you get a different behavior, it might shed more light on the part of the schema causing the issue. Adjusting the MAX_DEPTH value can also help in narrowing down the problem.

@TheBumpaster
Copy link
Author

TheBumpaster commented Aug 6, 2023

In reference to my old issue: giddyinc#64

The "Maximum call stack size exceeded" error usually indicates that there is a recursive loop running indefinitely. Given your Mongoose schema setup and the provided conversion code, it's highly likely that the infinite recursion is happening because of how the code handles nested schemas or references.

Let's try a step-by-step approach to debug and solve this:

  1. Detect and Prevent Infinite Recursion: We can introduce a depth check or a recursive-path check to stop the recursion after a certain depth or if the function comes across the same path more than once.
  2. Refactor the Recursive Calls: It's essential to handle the base cases and recursion properly to prevent such errors. If there is a cyclic reference in the Mongoose schema or any unintended recursive path, this will ensure it's caught.

Let's begin by adding a depth check:

Step 1: Add a depth check

To prevent infinite recursion, we'll add a depth parameter to the recursive functions and increase it with each recursive call. If the depth surpasses a certain threshold, we'll stop the recursion.

const MAX_DEPTH = 10;

const mapSchemaTypeToFieldSchema = ({ key = null, value, props, omitFields, depth = 0 }) => {
    if (depth > MAX_DEPTH) {
        throw new Error(`Max recursion depth of ${MAX_DEPTH} exceeded`);
    }
    // ... rest of the function ...

    if (swaggerType === 'array') {
        // ... other parts of the code ...
        const items = mapSchemaTypeToFieldSchema({ value: arraySchema || {}, props, omitFields, depth: depth + 1 });
        meta.items = items;
    }
    // ... rest of the function ...
};

const getFieldsFromMongooseSchema = (schema, options, depth = 0) => {
    if (depth > MAX_DEPTH) {
        throw new Error(`Max recursion depth of ${MAX_DEPTH} exceeded`);
    }
    // ... rest of the function ...
};

Step 2: Track recursive paths

Besides depth, another way to detect recursion is by tracking which paths you've visited. If a path is revisited, that means there's a cycle.

To achieve this, you can use an array or a set to track the paths that your function has visited:

const mapSchemaTypeToFieldSchema = ({ key = null, value, props, omitFields, depth = 0, visitedPaths = [] }) => {
    if (visitedPaths.includes(key)) {
        return { type: 'object' }; // or any default value to break the cycle
    }
    visitedPaths.push(key);
    // ... rest of the function ...
};

const getFieldsFromMongooseSchema = (schema, options, depth = 0, visitedPaths = []) => {
    // ... rest of the function ...
};

These changes should help detect and prevent infinite recursion. You may need to tweak the depth or adjust how you handle cyclic references based on your specific use case.

After implementing these changes, run your code. If it throws the "Max recursion depth exceeded" error, then you can be sure that the recursion depth is the issue. If it doesn't, but you get a different behavior, it might shed more light on the part of the schema causing the issue. Adjusting the MAX_DEPTH value can also help in narrowing down the problem.

I managed to resolve my issue. Mongoose will accept the following and generate a nice schema for me:

import { Schema, SchemaTypes } from 'mongoose'
import { IsomeSchema } from './interfaces'

const someSchema = new Schema<IsomeSchema>(
  {
    stringId: {
      type: 'string',
      required: true,
    },
    objectOne: {
      stringOne: 'string',
      stringTwo: 'string',
      stringThree: 'string',
      objectTwo: {
        type: 'string',
        required: true,
      },
      _id: false,
    },
    customObjectOne: {
      type: 'object',
      required: false,
    },
  },
  {
    timestamps: true,
    _id: true,
  }
)

export default someSchema 

But in m2s type: 'object' throws an error. So after changing it to SchemaTypes.Mixed it worked:

import { Schema, SchemaTypes } from 'mongoose'
import { IsomeSchema } from './interfaces'

const someSchema = new Schema<IsomeSchema>(
  {
    stringId: {
      type: 'string',
      required: true,
    },
    objectOne: {
      stringOne: 'string',
      stringTwo: 'string',
      stringThree: 'string',
      objectTwo: {
        type: 'string',
        required: true,
      },
      _id: false,
    },
    customObjectOne: {
      type: SchemaTypes.Mixed,
      required: false,
    },
  },
  {
    timestamps: true,
    _id: true,
  }
)

export default someSchema 

So if someone else also encounter this issue, make sure your schema types are written with prebuilt type definitions from Mongoose.

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