{"record":{"id":"52f14fd1aadbc986","repo":"apache/dolphinscheduler","slug":"cannot-parse-startjobrunrequest-from-json-start","errorCode":null,"errorMessage":"Cannot parse StartJobRunRequest from JSON: ${startJobRunRequestJson}","messagePattern":"Cannot parse StartJobRunRequest from JSON: (.+?)","errorType":"exception","errorClass":"EmrServerlessTaskException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-task-plugin/dolphinscheduler-task-emr-serverless/src/main/java/org/apache/dolphinscheduler/plugin/task/emrserverless/EmrServerlessTask.java","lineNumber":226,"sourceCode":"\n    /**\n     * Build StartJobRunRequest from parameters and user-provided JSON.\n     */\n    private StartJobRunRequest buildStartJobRunRequest() {\n        String startJobRunRequestJson;\n        try {\n            startJobRunRequestJson = ParameterUtils.convertParameterPlaceholders(\n                    emrServerlessParameters.getStartJobRunRequestJson(),\n                    ParameterUtils.convert(taskExecutionContext.getPrepareParamsMap()));\n        } catch (Exception e) {\n            throw new EmrServerlessTaskException(\"Failed to resolve parameter placeholders\", e);\n        }\n\n        StartJobRunRequest request;\n        try {\n            request = objectMapper.readValue(startJobRunRequestJson, StartJobRunRequest.class);\n        } catch (JsonProcessingException e) {\n            throw new EmrServerlessTaskException(\n                    \"Cannot parse StartJobRunRequest from JSON: \" + startJobRunRequestJson, e);\n        }\n\n        // Override applicationId and executionRoleArn from top-level parameters\n        request.setApplicationId(emrServerlessParameters.getApplicationId());\n        request.setExecutionRoleArn(emrServerlessParameters.getExecutionRoleArn());\n\n        // Set job name if provided\n        if (StringUtils.isNotEmpty(emrServerlessParameters.getJobName())) {\n            request.setName(emrServerlessParameters.getJobName());\n        } else {\n            request.setName(taskExecutionContext.getTaskName());\n        }\n\n        // Set client token for idempotency\n        request.setClientToken(taskExecutionContext.getTaskInstanceId() + \"-\" + System.currentTimeMillis());\n\n        return request;","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-task-plugin/dolphinscheduler-task-emr-serverless/src/main/java/org/apache/dolphinscheduler/plugin/task/emrserverless/EmrServerlessTask.java#L208-L244","documentation":"After placeholder resolution, the JSON string is deserialized into the AWS StartJobRunRequest model with Jackson (UpperCamelCase naming, FAIL_ON_UNKNOWN_PROPERTIES disabled). A JsonProcessingException means the JSON is syntactically invalid or not shaped like StartJobRunRequest; the failing JSON text is embedded in the message.","triggerScenarios":"objectMapper.readValue(startJobRunRequestJson, StartJobRunRequest.class) throws: malformed JSON (unquoted keys, trailing commas, single quotes), placeholder substitution produced invalid JSON, or keys don't map to StartJobRunRequest fields (e.g. lowercase 'jobDriver' field structure mismatch).","commonSituations":"Copy-pasted JSON with comments or trailing commas; nested quotes in sparkSubmitParameters broken escaping; substitution inserted unescaped quotes/newlines from a parameter value; using snake_case keys instead of UpperCamelCase required by this mapper.","solutions":["Read the offending JSON printed in the message and validate it with a JSON linter","Check the Jackson exception 'caused by' for line/column of the syntax error","Use UpperCamelCase field names matching the AWS SDK StartJobRunRequest (releaseLabel, jobDriver, executionRoleArn...)","Escape any quotes/newlines introduced by parameter substitution values","Test with a minimal valid request (releaseLabel + jobDriver) and add fields incrementally"],"exampleFix":"// before\n{\"jobDriver\":{\"sparkSubmit\":{\"entryPoint\":\"s3://b/${param}\"},}} // trailing comma\n// after\n{\"jobDriver\":{\"sparkSubmitJobDriver\":{\"entryPoint\":\"s3://b/x.py\",\"sparkSubmitParameters\":\"--conf spark.sql.x=y\"}}}","handlingStrategy":"validation","validationCode":"// dry-run the deserialization locally with the plugin's exact mapper configuration\ntry {\n    new JsonMapper.builder()\n        .configure(FAIL_ON_UNKNOWN_PROPERTIES, false)\n        .propertyNamingStrategy(new PropertyNamingStrategies.UpperCamelCaseStrategy())\n        .build()\n        .readTree(startJobRunRequestJson); // throws on malformed JSON\n} catch (JsonProcessingException e) {\n    throw new IllegalArgumentException(\"Invalid startJobRunRequestJson: \" + e.getOriginalMessage());\n}","typeGuard":null,"tryCatchPattern":"try {\n    request = objectMapper.readValue(startJobRunRequestJson, StartJobRunRequest.class);\n} catch (JsonProcessingException e) {\n    log.error(\"JSON invalid at line {} col {}: {}\",\n        e.getLocation().getLineNr(), e.getLocation().getColumnNr(), e.getOriginalMessage());\n    throw new TaskException(\"Fix startJobRunRequestJson\", e);\n}","preventionTips":["Validate the JSON with a linter before saving the task definition","Use UpperCamelCase keys matching AWS SDK StartJobRunRequest fields","Escape quotes/newlines in parameter values substituted into the JSON","Build the request incrementally: minimal releaseLabel+jobDriver first, then add fields"],"tags":["aws","emr-serverless","json","jackson"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}