Repository: parse-community/Parse-SDK-JS
Pull request #2623 (2025-05-24 23:47:25)

fix: Unhandled exception when calling `Parse.Cloud.run` with option value `null` (#2622)
## Pull Request

- Report security issues [confidentially](https://github.com/parse-community/Parse-SDK-JS/security/policy).
- Any contribution is under this [license](https://github.com/parse-community/Parse-SDK-JS/blob/alpha/LICENSE).
- Link this pull request to an [issue](https://github.com/parse-community/Parse-SDK-JS/issues?q=is%3Aissue).

This Pull Request is a fix for when passing null as a Parse.Cloud.run option 

## Issue
<!-- Add the link to the issue that this PR closes. -->

Closes: https://github.com/parse-community/Parse-SDK-JS/issues/2622
Closes: https://github.com/parse-community/parse-server/issues/9766

## Approach
<!-- Describe the changes in this PR. -->

## Tasks
<!-- Delete tasks that don't apply. -->

- [x] Add tests
- [ ] Add changes to documentation (guides, repository pages, code comments)


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **Bug Fixes**
  - Enhanced validation to accept only plain objects for the options parameter, preventing invalid input types.

- **Tests**
  - Added tests to ensure proper handling of options, including acceptance of empty or undefined values and rejection of invalid types.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

parse-github-assistant[bot]: 
🚀 Thanks for opening this pull request! 

<!-- parse-issue-bot-meta-tag-id {"suggestPr":false,"thanksFeature":false,"thanksPr":false} -->


coderabbitai[bot]: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->

> [!NOTE]
> Currently processing new changes in this PR. This may take a few minutes, please wait...
> 
> <details>
> <summary>📥 Commits</summary>
> 
> Reviewing files that changed from the base of the PR and between 24fa80d486c36026421474475c7fad69dd19b4d8 and 0eb66d7fb0031f29bd0e75e80672e102df301949.
> 
> </details>
> 
> <details>
> <summary>📒 Files selected for processing (2)</summary>
> 
> * `src/ParseObject.ts` (1 hunks)
> * `src/__tests__/ParseObject-test.js` (1 hunks)
> 
> </details>
> 
> ```ascii
>  _____________________________________________________
> < Making Elsa proud by letting it go...to production. >
>  -----------------------------------------------------
>   \
>    \   (\__/)
>        (•ㅅ•)
>        / 　 づ
> ```

<!-- end of auto-generated comment: review in progress by coderabbit.ai -->
<!-- usage_tips_start -->

> [!TIP]
> <details>
> <summary>CodeRabbit can use oxc to improve the quality of JavaScript and TypeScript code reviews.</summary>
> 
> Add a [configuration file](https://github.com/oxc-project/oxc) to your project to customize how CodeRabbit runs oxc.
> 
> </details>

<!-- usage_tips_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=parse-community/Parse-SDK-JS&utm_content=2623):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
mtrezza: @coderabbitai review
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/parse-community/Parse-SDK-JS/pull/2623?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`24fa80d`)](https://app.codecov.io/gh/parse-community/Parse-SDK-JS/commit/24fa80d486c36026421474475c7fad69dd19b4d8?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community) to head [(`0eb66d7`)](https://app.codecov.io/gh/parse-community/Parse-SDK-JS/commit/0eb66d7fb0031f29bd0e75e80672e102df301949?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff            @@
##             alpha     #2623   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           63        63           
  Lines         6193      6195    +2     
  Branches      1460      1473   +13     
=========================================
+ Hits          6193      6195    +2     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/parse-community/Parse-SDK-JS/pull/2623?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
modime: @mtrezza Thanks for the feedback. Update this MR as you see fit. My take on this was mostly a bug fix: If "no options" then return an empty bracket, i.e. handle `null` the same as `undefined` (and also return early in the code when there are no options to act on).

We found this error in `Parse.Cloud.run` because our tests with options set to null, expects an `Invalid request.` error with the error code `141`. 
modime: > I believe when throwing like suggested it should return a proper error, instead of an internal server error. We'd have to see in the test. Would you want to incorporate the changes?

No, better you do it. I am unable to make changes for the next week as I am traveling and have limited access to the source code.

Patch:
diff --git a/src/ParseObject.ts b/src/ParseObject.ts
index 9ecb329..59a4866 100644
--- a/src/ParseObject.ts
+++ b/src/ParseObject.ts
@@ -514,6 +514,9 @@ class ParseObject<T extends Attributes = Attributes> {
 
   static _getRequestOptions(options: RequestOptions & FullOptions & { json?: boolean } = {}) {
     const requestOptions: RequestOptions & FullOptions & { json?: boolean } = {};
+    if (Object.prototype.toString.call(options) !== '[object Object]') {
+      throw new Error('request options must be of type Object');
+    }
     const { hasOwn } = Object;
     if (hasOwn(options, 'useMasterKey')) {
       requestOptions.useMasterKey = !!options.useMasterKey;


Test patch:
diff --git a/src/__tests__/Cloud-test.js b/src/__tests__/Cloud-test.js
index 6ed1e84..dba85b2 100644
--- a/src/__tests__/Cloud-test.js
+++ b/src/__tests__/Cloud-test.js
@@ -356,4 +356,30 @@ describe('CloudController', () => {
     });
     expect(options.useMasterKey).toBe(false);
   });
+
+  it('run passes with empty options', () => {
+    const values = [undefined, {}];
+
+    const mockRun = jest.fn();
+    mockRun.mockReturnValue(Promise.resolve({ result: {} }));
+
+    CoreManager.setCloudController({
+      run: mockRun,
+      getJobsData: jest.fn(),
+      startJob: jest.fn(),
+    });
+
+    for (const value of values) {
+      mockRun.mockClear();
+      expect(() => Cloud.run('myfunction', {}, value)).not.toThrow();
+      expect(mockRun).toHaveBeenLastCalledWith('myfunction', {}, {});
+    }
+  });
+
+  it('run throws with invalid options', () => {
+    const values = [null, []];
+    for (const value of values) {
+      expect(() => Cloud.run('myfunction', {}, value)).toThrow();
+    }
+  });
 });