{"record":{"id":"8cbdc0bc9bb03bae","repo":"apache/dolphinscheduler","slug":"failed-to-get-job-run-status","errorCode":null,"errorMessage":"Failed to get job run status","messagePattern":"Failed to get job run status","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":257,"sourceCode":"        }\n\n        // Set client token for idempotency\n        request.setClientToken(taskExecutionContext.getTaskInstanceId() + \"-\" + System.currentTimeMillis());\n\n        return request;\n    }\n\n    /**\n     * Get the current state of the job run.\n     */\n    private String getJobRunState() {\n        GetJobRunRequest request = new GetJobRunRequest()\n                .withApplicationId(emrServerlessParameters.getApplicationId())\n                .withJobRunId(jobRunId);\n        GetJobRunResult result = emrServerlessClient.getJobRun(request);\n\n        if (result == null || result.getJobRun() == null) {\n            throw new EmrServerlessTaskException(\"Failed to get job run status\");\n        }\n\n        JobRun jobRun = result.getJobRun();\n        String state = jobRun.getState();\n        log.info(\"EMR Serverless job run [applicationId:{}, jobRunId:{}] state: {}\",\n                emrServerlessParameters.getApplicationId(), jobRunId, state);\n        return state;\n    }\n\n    /**\n     * Map EMR Serverless job run final state to DolphinScheduler exit code.\n     */\n    private int mapStateToExitCode(String state) {\n        if (state == null) {\n            return TaskConstants.EXIT_CODE_FAILURE;\n        }\n        if (JobRunState.SUCCESS.toString().equals(state)) {\n            return TaskConstants.EXIT_CODE_SUCCESS;","sourceCodeStart":239,"sourceCodeEnd":275,"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#L239-L275","documentation":"getJobRunState polls GetJobRun for the current job run state. If the response or its jobRun object is null, the plugin cannot determine the state and throws EmrServerlessTaskException with this message; the caller trackApplicationStatus catches it and marks the task EXIT_CODE_FAILURE.","triggerScenarios":"emrServerlessClient.getJobRun(request) returns a result without a JobRun body — AWS returned an empty/unexpected response (e.g. jobRunId no longer resolvable against applicationId, race during cancellation, or a mocked/proxied endpoint like LocalStack returning empty bodies).","commonSituations":"Testing against LocalStack or a mock endpoint with partial GetJobRun support; jobRunId recovered from appIds refers to a job run deleted or belonging to a different application; transient AWS response anomaly.","solutions":["Verify applicationId and jobRunId pair is correct (recovered appIds may be stale or from a different application)","Check AWS console: does the job run still exist for this application?","If using a custom endpoint (emr.serverless.endpoint / EMR_SERVERLESS_ENDPOINT), confirm the mock supports GetJobRun returning a JobRun body","Retry the task; if persistent, inspect worker networking/region settings"],"exampleFix":"// before (recovered id may be wrong)\njobRunId = getAppIds();\n// after\njobRunId = getAppIds();\nif (StringUtils.length(jobRunId) != 0 && !jobRunId.matches(\"[0-9a-f]{8}.*\")) {\n    throw new EmrServerlessTaskException(\"appIds does not look like a jobRunId: \" + jobRunId);\n}","handlingStrategy":"retry","validationCode":"// confirm the job run exists before polling\nString recovered = getAppIds();\nif (StringUtils.isNotBlank(recovered)) {\n    try {\n        emrServerlessClient.getJobRun(new GetJobRunRequest()\n            .withApplicationId(appId).withJobRunId(recovered)).getJobRun().getState();\n    } catch (Exception e) {\n        log.warn(\"Recovered jobRunId {} not resolvable: {}\", recovered, e.getMessage());\n    }\n}","typeGuard":"boolean isValidJobRunResult(GetJobRunResult r) {\n    return r != null && r.getJobRun() != null && StringUtils.isNotEmpty(r.getJobRun().getState());\n}","tryCatchPattern":"int attempts = 0;\nwhile (attempts++ < 3) {\n    try {\n        String state = getJobRun(jobRunId);\n        break;\n    } catch (EmrServerlessTaskException e) {\n        if (attempts == 3) { setExitStatusCode(EXIT_CODE_FAILURE); break; }\n        TimeUnit.SECONDS.sleep(5);\n    }\n}","preventionTips":["Don't hand-edit appIds; keep the exact jobRunId from StartJobRun","When testing, use an endpoint mock that fully supports GetJobRun bodies","Pin client region to the application's region so GetJobRun resolves","Alert on repeated empty GetJobRun responses in worker logs"],"tags":["aws","emr-serverless","empty-response","polling"],"backgroundTag":"empty-api-response","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}