Skip to content

[ZEPPELIN-6012] Fix NPE when the run-note request body carries no params - #5385

Open
big-cir wants to merge 1 commit into
apache:masterfrom
big-cir:ZEPPELIN-6012
Open

[ZEPPELIN-6012] Fix NPE when the run-note request body carries no params#5385
big-cir wants to merge 1 commit into
apache:masterfrom
big-cir:ZEPPELIN-6012

Conversation

@big-cir

@big-cir big-cir commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

What is this PR for?

POST /api/notebook/job/{noteId} accepts an optional request body carrying form parameters. Sending a body that supplies no parameters, either {} or {"params":null}, returns HTTP 500.

ParametersRequest declares its params field as final and assigns it in the constructor, but Gson never invokes that constructor. It allocates the instance and fills the fields reflectively, so a body without a "params" entry leaves the field at its default value of null. NotebookRestApi.runNoteJobs then hands that null straight to HashMap.putAll:

Map<String, Object> params = new HashMap<>();
if (!StringUtils.isEmpty(message)) {
  ParametersRequest request = GSON.fromJson(message, ParametersRequest.class);
  params.putAll(request.getParams());
}

{} is not an empty string, so the guard passes and the call throws:

java.lang.NullPointerException: Cannot invoke "java.util.Map.size()" because "m" is null
	at java.util.HashMap.putMapEntries(HashMap.java:495)
	at java.util.HashMap.putAll(HashMap.java:783)
	at org.apache.zeppelin.rest.NotebookRestApi.runNoteJobs(NotebookRestApi.java:850)

Nothing catches it, so WebApplicationExceptionMapper turns it into a generic Internal server error with status 500. Running a note without form parameters is a legitimate request, and an empty body already works, so both spellings should behave the same.

This PR makes ParametersRequest.getParams() return an empty map instead of null, which covers both an absent key and an explicit null value.

Scope note: two other call sites parse the same request object, at NotebookRestApi lines 979 and 1018. Both assign the result to a local variable rather than calling putAll, so they do not throw, and their consumers already guard against null (Note.runAllSync and NotebookService.runParagraph each check params != null && !params.isEmpty()). Fixing the accessor covers all three call sites without changing their behavior.

What type of PR is it?

Bug Fix

Todos

  • - Return an empty map from ParametersRequest.getParams() when no parameters were supplied
  • - Add a regression test covering both {} and {"params":null}
  • - Confirm the test fails without the fix and passes with it

What is the Jira issue?

How should this be tested?

New test NotebookRestApiTest#testRunNoteWithoutParamsInBody creates a note and posts both bodies to the run-note endpoint, asserting that each returns status OK.

./mvnw package -pl zeppelin-server --am \
  -Dtest='NotebookRestApiTest#testRunNoteWithoutParamsInBody' -DfailIfNoTests=false

Reverting only the production change makes the new test fail with Expected: HTTP response <200> but: got <500>, and the server log shows the stack trace above. With the fix it passes.

Also verified by hand against a locally running server, posting each body to /api/notebook/job/{noteId}:

Request body Before After
{} HTTP 500 HTTP 200
{"params":null} HTTP 500 HTTP 200
empty body HTTP 200 HTTP 200
{"params":{"name":"zeppelin"}} HTTP 200 HTTP 200

Screenshots (if appropriate)

N/A

Questions:

  • Does the license files need to update? No
  • Is there breaking changes for older versions? No
  • Does this needs documentation? No

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

Successfully merging this pull request may close these issues.

1 participant