{"record":{"id":"08fff42917a7a421","repo":"apache/beam","slug":"please-provide-a-row-mapper","errorCode":null,"errorMessage":"please provide a row mapper","messagePattern":"please provide a row mapper","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/neo4j/src/main/java/org/apache/beam/sdk/io/neo4j/Neo4jIO.java","lineNumber":593,"sourceCode":"      if (transactionConfig == null) {\n        transactionConfig = TransactionConfig.empty();\n      }\n\n      Boolean writeTransaction = getProvidedValue(getWriteTransaction());\n      if (writeTransaction == null) {\n        writeTransaction = Boolean.FALSE;\n      }\n\n      Boolean logCypher = getProvidedValue(getLogCypher());\n      if (logCypher == null) {\n        logCypher = Boolean.FALSE;\n      }\n\n      if (driverProviderFn == null) {\n        throw new RuntimeException(\"please provide a driver provider\");\n      }\n      if (rowMapper == null) {\n        throw new RuntimeException(\"please provide a row mapper\");\n      }\n      if (parametersFunction == null) {\n        parametersFunction = t -> Collections.emptyMap();\n      }\n\n      ReadFn<ParameterT, OutputT> readFn =\n          new ReadFn<>(\n              driverProviderFn,\n              sessionConfig,\n              transactionConfig,\n              cypher,\n              rowMapper,\n              parametersFunction,\n              writeTransaction,\n              logCypher);\n\n      return getOutputPCollection(input, readFn, getCoder());\n    }","sourceCodeStart":575,"sourceCodeEnd":611,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/neo4j/src/main/java/org/apache/beam/sdk/io/neo4j/Neo4jIO.java#L575-L611","documentation":"Neo4jIO's Read transform expand() validates that all required configuration has been set on the builder before wiring up the ReadFn. The rowMapper (a RowMapper<OutputT>) converts each Neo4j Result record into the pipeline's output type; without it the transform cannot produce elements, so it fails fast at graph-construction time with a RuntimeException.","triggerScenarios":"Calling Neo4jIO.<T>read() (or readAll) and expanding the transform without having called .withRowMapper(...) on the builder, or explicitly passing null.","commonSituations":"Copy-pasting a read example that only sets cypher/driverProvider and forgetting the mapper; refactoring that removed the mapper call; building the Read spec dynamically where a conditional branch skipped withRowMapper.","solutions":["Call .withRowMapper(rowMapper) on the Neo4jIO.Read builder before expand(), supplying a lambda that maps org.neo4j.driver.Record to your output type.","If you intended GenericRecord-style output, still provide a mapper that extracts fields from the Record.","Verify the builder variable being expanded is the fully configured one, not a partially built intermediate."],"exampleFix":"// before\nNeo4jIO.<String>read().withDriverProviderFn(() -> GraphDatabase.driver(url))\n// after\nNeo4jIO.<String>read()\n  .withDriverProviderFn(() -> GraphDatabase.driver(url))\n  .withCypher(\"MATCH (n:Person) RETURN n.name AS name\")\n  .withRowMapper(record -> record.get(\"name\").asString())","handlingStrategy":"validation","validationCode":"if (readSpec.getRowMapper() == null) throw new IllegalStateException(\"Call .withRowMapper() before expand()\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always chain withCypher + withRowMapper + withDriverProviderFn together when building Neo4jIO.Read.","Add a unit test that constructs the read spec fully before expanding."],"tags":["java","neo4j","apache-beam","missing-required-configuration"],"backgroundTag":"missing-required-argument","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"}