Skip to content

[AWS] Custom Runtime error response format inconsistent with Lambda Runtime #1428

Description

@mrjv

Description

When a Spring Cloud Function throws an exception, the error response JSON returned by the Custom Runtime uses a different stackTrace format than the standard Lambda Runtime. This makes it difficult to parse error responses consistently across runtime types:

  • Lambda Runtime returns stackTrace as a JSON array of strings (one entry per frame).
  • Custom Runtime returns stackTrace as a single string with newline-separated frames (including Caused by sections inlined).

Reproducing Code

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public Function<Map<String, String>, String> hello() {
        return event -> {
            throw new RuntimeException("Something went wrong");
        };
    }

    @Bean
    public Function<Map<String, String>, String> helloNested() {
        return event -> {
            Exception cause = new IllegalStateException("Root cause error");
            throw new RuntimeException("Wrapper exception", cause);
        };
    }
}

Lambda Runtime Response — Simple Exception

{
  "errorMessage": "Something went wrong",
  "errorType": "java.lang.RuntimeException",
  "stackTrace": [
    "com.example.lambda.Application.lambda$hello$0(Application.java:24)",
    "org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunctionAndEnrichResultIfNecessary(SimpleFunctionRegistry.java:1027)",
    "org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunction(SimpleFunctionRegistry.java:973)",
    "org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.doApply(SimpleFunctionRegistry.java:811)",
    "org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.apply(SimpleFunctionRegistry.java:635)",
    "org.springframework.cloud.function.adapter.aws.FunctionInvoker.handleRequest(FunctionInvoker.java:94)",
    "java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)",
    "java.base/java.lang.reflect.Method.invoke(Unknown Source)"
  ]
}

Custom Runtime Response — Simple Exception

{
  "errorType": "RuntimeException",
  "errorMessage": "Something went wrong",
  "stackTrace": "java.lang.RuntimeException: Something went wrong\n\tat com.example.lambda.Application.lambda$hello$0(Application.java:24)\n\tat org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunctionAndEnrichResultIfNecessary(SimpleFunctionRegistry.java:1027)\n\tat org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunction(SimpleFunctionRegistry.java:973)\n\tat org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.doApply(SimpleFunctionRegistry.java:811)\n\tat org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.apply(SimpleFunctionRegistry.java:635)\n\tat org.springframework.cloud.function.adapter.aws.CustomRuntimeEventLoop.eventLoop(CustomRuntimeEventLoop.java:153)\n\tat org.springframework.cloud.function.adapter.aws.CustomRuntimeEventLoop.lambda$run$0(CustomRuntimeEventLoop.java:95)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)\n\tat java.base/java.lang.Thread.run(Thread.java:1474)\n"
}

Lambda Runtime Response — Nested Exception

{
  "errorMessage": "Wrapper exception",
  "errorType": "java.lang.RuntimeException",
  "stackTrace": [
    "com.example.lambda.Application.lambda$helloNested$0(Application.java:36)",
    "org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunctionAndEnrichResultIfNecessary(SimpleFunctionRegistry.java:1027)",
    "org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunction(SimpleFunctionRegistry.java:973)",
    "org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.doApply(SimpleFunctionRegistry.java:811)",
    "org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.apply(SimpleFunctionRegistry.java:635)",
    "org.springframework.cloud.function.adapter.aws.FunctionInvoker.handleRequest(FunctionInvoker.java:94)",
    "java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)",
    "java.base/java.lang.reflect.Method.invoke(Unknown Source)"
  ]
}

Custom Runtime Response — Nested Exception

{
  "errorType": "RuntimeException",
  "errorMessage": "Wrapper exception",
  "stackTrace": "java.lang.RuntimeException: Wrapper exception\n\tat com.example.lambda.Application.lambda$helloNested$0(Application.java:36)\n\tat org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunctionAndEnrichResultIfNecessary(SimpleFunctionRegistry.java:1027)\n\tat org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunction(SimpleFunctionRegistry.java:973)\n\tat org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.doApply(SimpleFunctionRegistry.java:811)\n\tat org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.apply(SimpleFunctionRegistry.java:635)\n\tat org.springframework.cloud.function.adapter.aws.CustomRuntimeEventLoop.eventLoop(CustomRuntimeEventLoop.java:153)\n\tat org.springframework.cloud.function.adapter.aws.CustomRuntimeEventLoop.lambda$run$0(CustomRuntimeEventLoop.java:95)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)\n\tat java.base/java.lang.Thread.run(Thread.java:1474)\nCaused by: java.lang.IllegalStateException: Root cause error\n\tat com.example.lambda.Application.lambda$helloNested$0(Application.java:35)\n\t... 9 more\n"
}

Expected Behavior

The Custom Runtime should return stackTrace in the same format as the Lambda Runtime — a JSON array of strings with one stack frame per element — to allow consistent error parsing regardless of deployment target.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions