{"record":{"id":"a90a11905edc8031","repo":"apache/beam","slug":"max-past-must-be-a-positive-long-value","errorCode":null,"errorMessage":"'max-past' must be a positive long value.","messagePattern":"'max-past' must be a positive long value\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/meta/provider/datagen/DataGeneratorRowFn.java","lineNumber":187,"sourceCode":"        return (index) -> minD + (maxD - minD) * ThreadLocalRandom.current().nextDouble();\n      case TINYINT:\n      case SMALLINT:\n      case INTEGER:\n      case BIGINT:\n        long minL = properties.path(\"fields.\" + fieldName + \".min\").asLong(0L);\n        long maxL = properties.path(\"fields.\" + fieldName + \".max\").asLong(Long.MAX_VALUE);\n        return (index) -> minL + (long) (ThreadLocalRandom.current().nextDouble() * (maxL - minL));\n      case DECIMAL:\n        double minBd = properties.path(\"fields.\" + fieldName + \".min\").asDouble(0.0);\n        double maxBd = properties.path(\"fields.\" + fieldName + \".max\").asDouble(1000.0);\n        return (index) ->\n            BigDecimal.valueOf(minBd + (maxBd - minBd) * ThreadLocalRandom.current().nextDouble());\n      case TIMESTAMP:\n        JsonNode maxPastNode = properties.path(\"fields.\" + fieldName + \".max-past\");\n        if (!maxPastNode.isMissingNode()) {\n          long maxPastMs = maxPastNode.asLong();\n          if (maxPastMs <= 0) {\n            throw new IllegalArgumentException(\"'max-past' must be a positive long value.\");\n          }\n          return (index) ->\n              Instant.now()\n                  .minus(\n                      Duration.millis(\n                          (long) (ThreadLocalRandom.current().nextDouble() * maxPastMs)));\n        }\n        return (index) -> Instant.now();\n      default:\n        throw new UnsupportedOperationException(\"Unsupported SQL type for datagen: \" + sqlTypeName);\n    }\n  }\n}\n","sourceCodeStart":169,"sourceCodeEnd":201,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/meta/provider/datagen/DataGeneratorRowFn.java#L169-L201","documentation":"For TIMESTAMP fields, the optional 'fields.<name>.max-past' property controls how far back in the past random timestamps may fall. It must parse to a strictly positive long (milliseconds). Zero or negative values throw an IllegalArgumentException.","triggerScenarios":"Setting fields.<name>.max-past to 0, a negative number, or a non-numeric value that asLong coerces to <= 0, on a TIMESTAMP datagen field.","commonSituations":"Configuring max-past: 0 thinking it disables the option; using a negative duration intending 'in the past'; pasting a duration string like '5m' that Jackson coerces to 0.","solutions":["Set 'max-past' to a positive integer millisecond value (e.g. 600000 for 10 minutes).","Remove the 'max-past' property entirely to use the default (Instant.now()).","Convert duration strings to milliseconds before writing the property."],"exampleFix":"// before\n'{\"fields\":{\"ts\":{\"max-past\":0}}}'\n// after\n'{\"fields\":{\"ts\":{\"max-past\":600000}}}'","handlingStrategy":"validation","validationCode":"JsonNode p = props.path(\"fields.\" + name + \".max-past\");\nif (!p.isMissingNode() && p.asLong() <= 0) {\n  throw new IllegalArgumentException(\"max-past must be > 0\");\n}","typeGuard":null,"tryCatchPattern":"try { buildRowFn(props); } catch (IllegalArgumentException e) { /* remove or correct max-past */ }","preventionTips":["Use positive millisecond integers only.","Remove the key instead of setting 0 to use defaults."],"tags":["beam-sql","datagen","config-validation"],"backgroundTag":"invalid-config-value","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}