{"record":{"id":"a9a8a59c8d745e20","repo":"prestodb/presto","slug":"plan-serialization-error","errorCode":"PLAN_SERIALIZATION_ERROR","errorMessage":"Cannot serialize plan to JSON","messagePattern":"Cannot serialize plan to JSON","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/sql/planner/CanonicalPlan.java","lineNumber":91,"sourceCode":"        return Objects.hash(plan, strategy);\n    }\n\n    @Override\n    public String toString()\n    {\n        return toStringHelper(this)\n                .add(\"plan\", plan)\n                .add(\"strategy\", strategy)\n                .toString();\n    }\n\n    public String toString(ObjectMapper objectMapper)\n    {\n        try {\n            return objectMapper.writeValueAsString(this);\n        }\n        catch (JsonProcessingException e) {\n            throw new PrestoException(PLAN_SERIALIZATION_ERROR, \"Cannot serialize plan to JSON\", e);\n        }\n    }\n}\n","sourceCodeStart":73,"sourceCodeEnd":95,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/sql/planner/CanonicalPlan.java#L73-L95","documentation":"CanonicalPlan.toString(ObjectMapper) serializes the canonical plan to JSON for logging/transport. If Jackson raises a JsonProcessingException (non-serializable field, invalid state, missing serializer), Presto wraps it in PLAN_SERIALIZATION_ERROR. This indicates the canonical plan contains something the configured ObjectMapper cannot represent.","triggerScenarios":"Calling toString(objectMapper) on a CanonicalPlan whose members include types lacking Jackson serializers (custom handles, lambdas, unregistered types) or a broken module registration in the ObjectMapper.","commonSituations":"Custom connectors/plugins adding plan metadata not covered by Jackson modules; version upgrades changing serialization annotations; constructing CanonicalPlan with a CanonicalTableHandle referencing a non-serializable connector object.","solutions":["Ensure the ObjectMapper used has all required Jackson modules registered (e.g. Presto's json codecs for handles, types, plan nodes)","Find and fix the offending field in the canonical plan (see the cause JsonProcessingException in the stack trace)","Report/upgrade if triggered by core Presto plan nodes after a version upgrade"],"exampleFix":"// before\nObjectMapper plainMapper = new ObjectMapper();\nString json = canonicalPlan.toString(plainMapper);\n// after\nObjectMapper mapper = jsonMapperFactory(); // includes Presto modules\nmapper.registerModule(new SimpleModule().addSerializer(MyHandle.class, new MyHandleSerializer()));\nString json = canonicalPlan.toString(mapper);","handlingStrategy":"try-catch","validationCode":"// Pre-flight: ensure the mapper can serialize before asking the plan to\ntry { mapper.writeValueAsString(planProbeFields); } catch (JsonProcessingException e) { /* register missing modules first */ }","typeGuard":null,"tryCatchPattern":"try { String json = canonicalPlan.toString(mapper); } catch (PrestoException e) { if (e.getErrorCode().equals(PLAN_SERIALIZATION_ERROR.toErrorCode())) { registerMissingJacksonModules(mapper); retry(); } else throw e; }","preventionTips":["Always build ObjectMappers via Presto's json mapper factory with all plugin modules registered","Keep connector handles serializable (implement proper Jackson annotations)","Keep coordinator and worker Presto versions aligned"],"tags":["json","serialization","canonical-plan"],"backgroundTag":"plan-serialization-failed","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}