{"record":{"id":"eac1ce231669911d","repo":"apache/beam","slug":"cannot-encode-a-null-readableduration","errorCode":null,"errorMessage":"cannot encode a null ReadableDuration","messagePattern":"cannot encode a null ReadableDuration","errorType":"exception","errorClass":"CoderException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/coders/DurationCoder.java","lineNumber":60,"sourceCode":"      new TypeDescriptor<ReadableDuration>() {};\n\n  private static final VarLongCoder LONG_CODER = VarLongCoder.of();\n\n  private DurationCoder() {}\n\n  private Long toLong(ReadableDuration value) {\n    return value.getMillis();\n  }\n\n  private ReadableDuration fromLong(Long decoded) {\n    return Duration.millis(decoded);\n  }\n\n  @Override\n  public void encode(ReadableDuration value, OutputStream outStream)\n      throws CoderException, IOException {\n    if (value == null) {\n      throw new CoderException(\"cannot encode a null ReadableDuration\");\n    }\n    LONG_CODER.encode(toLong(value), outStream);\n  }\n\n  @Override\n  public ReadableDuration decode(InputStream inStream) throws CoderException, IOException {\n    return fromLong(LONG_CODER.decode(inStream));\n  }\n\n  @Override\n  public void verifyDeterministic() {\n    LONG_CODER.verifyDeterministic();\n  }\n\n  /**\n   * {@inheritDoc}\n   *\n   * @return {@code true}. This coder is injective.","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/DurationCoder.java#L42-L78","documentation":"DurationCoder.encode rejects null ReadableDuration values with CoderException: the coder encodes durations as a VarLong of milliseconds and has no null representation. Null durations must be handled upstream or with a nullable wrapper coder.","triggerScenarios":"Encoding a PCollection containing a null org.joda.time.ReadableDuration (e.g. from a MapElements that returns null duration), when the resolved coder is DurationCoder.","commonSituations":"Computing durations between events where one side is missing; mapping Option/nullable fields directly to Duration; Kafka/parse pipelines producing null gaps.","solutions":["Filter or default null durations before the encoding point (e.g. Duration.ZERO or skip).","Wrap with NullableCoder.of(DurationCoder.of()) for nullable duration collections.","Fix the producing transform to return a non-null duration (e.g. use Duration.millis(0) as sentinel).","Change the element type to Optional<Duration> with a supporting coder."],"exampleFix":"// before\n.apply(MapElements.into(TypeDescriptor.of(ReadableDuration.class)).via(e -> e.getEnd() != null ? new Duration(e.getStart(), e.getEnd()) : null))\n\n// after\n.apply(Filter.by(e -> e.getEnd() != null))\n.apply(MapElements.into(TypeDescriptor.of(ReadableDuration.class)).via(e -> new Duration(e.getStart(), e.getEnd())))","handlingStrategy":"type-guard","validationCode":"if (duration == null) { duration = Duration.ZERO; /* or skip record */ }","typeGuard":"boolean isEncodable(ReadableDuration d) { return d != null; }","tryCatchPattern":"try {\n  pipeline.run().waitUntilFinish();\n} catch (RuntimeException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"null ReadableDuration\")) {\n    // add null filtering or NullableCoder.of(DurationCoder.of())\n  }\n  throw e;\n}","preventionTips":["Compute durations defensively; default missing endpoints to Duration.ZERO or drop records.","Wrap with NullableCoder.of when null durations are valid domain values."],"tags":["beam","java","coders","null","joda-time"],"backgroundTag":"null-argument","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}