{"record":{"id":"4dbf8f16581eb84e","repo":"floci-io/floci","slug":"failed-to-serialize-proxy-event","errorCode":null,"errorMessage":"Failed to serialize proxy event","messagePattern":"Failed to serialize proxy event","errorType":"exception","errorClass":"RuntimeException","httpStatus":500,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/services/apigateway/ApiGatewayExecuteController.java","lineNumber":765,"sourceCode":"                    if (value != null) {\n                        authorizerNode.put(key, value.toString());\n                    }\n                });\n            }\n        }\n\n        if (body != null && body.length > 0) {\n            event.put(\"body\", new String(body));\n            event.put(\"isBase64Encoded\", false);\n        } else {\n            event.putNull(\"body\");\n            event.put(\"isBase64Encoded\", false);\n        }\n\n        try {\n            return objectMapper.writeValueAsString(event);\n        } catch (Exception e) {\n            throw new RuntimeException(\"Failed to serialize proxy event\", e);\n        }\n    }\n\n    // Package-private for unit testing (see ApiGatewayExecuteControllerTest).\n    void putSingleValueHeaders(ObjectNode event, HttpHeaders headers) {\n        ObjectNode headersNode = event.putObject(\"headers\");\n        headers.getRequestHeaders().forEach((name, values) -> {\n            // AWS collapses duplicate request headers to the LAST value in the single-value `headers`\n            // map (multiValueHeaders keeps every value). Taking the first value diverged from AWS.\n            if (!values.isEmpty()) {\n                headersNode.put(name, values.get(values.size() - 1));\n            }\n        });\n    }\n\n    void putMultiValueHeaders(ObjectNode event, HttpHeaders headers) {\n        ObjectNode mvHeaders = event.putObject(\"multiValueHeaders\");\n        headers.getRequestHeaders().forEach((name, values) -> {","sourceCodeStart":747,"sourceCodeEnd":783,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/services/apigateway/ApiGatewayExecuteController.java#L747-L783","documentation":"While building a Lambda proxy (payload v1/v2) event for an API Gateway execute-api invocation, ApiGatewayExecuteController serializes the assembled ObjectNode with objectMapper.writeValueAsString(event). Jackson declares JsonProcessingException, so the code wraps any failure in RuntimeException('Failed to serialize proxy event'). On ObjectNode trees with only String/boolean/null values this practically never fires; when it does it means the ObjectMapper is misconfigured (custom/failing serializers, blocked modules) rather than bad request data.","triggerScenarios":"Invoking an execute-api endpoint backed by a Lambda proxy integration (POST/GET on the stage path) while the injected ObjectMapper has a registered module or custom serializer that throws for the node types used (body, isBase64Encoded, headers). Also possible with a corrupted Jackson runtime after dependency shading or version conflicts in a custom Floci build.","commonSituations":"Custom Floci forks that replace/annotate the ObjectMapper (e.g. a module that serializes dates oddly), native-image builds where a Jackson serializer lacks reflection metadata, or Jackson version clashes introduced by an added dependency. For stock Floci the path is effectively unreachable.","solutions":["Treat this as a server defect, not a client error: it maps to HTTP 500, so fix the emulator configuration, not the request.","Check for a custom ObjectMapper binding or added Jackson module in your build (Quarkus CDI producer, ObjectMapper customizer) and remove/fix it.","Verify Jackson dependency versions with `./mvnw dependency:tree -Dincludes=com.fasterxml.jackson.*` and align them with the Quarkus BOM.","For native-image builds, add the affected serializer classes to reflection registers and re-test.","As an upstream fix, wrap JsonProcessingException and log the offending event node so the failure is diagnosable."],"exampleFix":"// before\ntry {\n    return objectMapper.writeValueAsString(event);\n} catch (Exception e) {\n    throw new RuntimeException(\"Failed to serialize proxy event\", e);\n}\n// after: keep the 500 but make it diagnosable\ntry {\n    return objectMapper.writeValueAsString(event);\n} catch (JsonProcessingException e) {\n    LOG.errorf(e, \"Proxy event serialization failed; event=%s\", event);\n    throw new IllegalStateException(\"Failed to serialize proxy event\", e);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Floci maintainer: fail loudly and log the node so the config defect is visible\ntry {\n    return objectMapper.writeValueAsString(event);\n} catch (JsonProcessingException e) {\n    LOG.errorf(e, \"Proxy event serialization failed; event=%s\", event);\n    throw new IllegalStateException(\"Failed to serialize proxy event\", e);\n}","preventionTips":["Do not override the application ObjectMapper with custom serializers in an emulator build.","Keep Jackson versions pinned by the Quarkus BOM; run dependency:tree after adding dependencies.","Cover proxy-event serialization with the existing unit tests (ApiGatewayExecuteControllerTest) in both plain and native profiles.","Remember this is a 500-class emulator bug; retrying the same HTTP call will not help."],"tags":["serialization","jackson","lambda","proxy-integration","server-error"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}