{"record":{"id":"daef33e9d01788f0","repo":"apache/beam","slug":"failed-to-build-transform-from-spec-s-s","errorCode":null,"errorMessage":"Failed to build transform from spec %s: %s","messagePattern":"Failed to build transform from spec (.+?): (.+?)","errorType":"exception","errorClass":"java.lang.RuntimeException","httpStatus":null,"severity":"error","filePath":"sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/ExpansionService.java","lineNumber":337,"sourceCode":"  }\n\n  private static class TransformProviderForBuilder implements TransformProvider {\n\n    private final ExternalTransformBuilder transformBuilder;\n\n    private TransformProviderForBuilder(ExternalTransformBuilder transformBuilder) {\n      this.transformBuilder = transformBuilder;\n    }\n\n    @Override\n    public PTransform getTransform(RunnerApi.FunctionSpec spec, PipelineOptions options) {\n      try {\n        Class configClass = getConfigClass(transformBuilder);\n        return transformBuilder.buildExternal(\n            payloadToConfig(\n                ExternalConfigurationPayload.parseFrom(spec.getPayload()), configClass));\n      } catch (Exception e) {\n        throw new RuntimeException(\n            String.format(\"Failed to build transform from spec %s: %s\", spec, e.getMessage()), e);\n      }\n    }\n\n    @Override\n    public List<String> getDependencies(RunnerApi.FunctionSpec spec, PipelineOptions options) {\n      try {\n        Class configClass = getConfigClass(transformBuilder);\n        Optional<List<String>> dependencies =\n            transformBuilder.getDependencies(\n                payloadToConfig(\n                    ExternalConfigurationPayload.parseFrom(spec.getPayload()), configClass),\n                options);\n        return dependencies.orElseGet(() -> TransformProvider.super.getDependencies(spec, options));\n      } catch (Exception e) {\n        throw new RuntimeException(\n            String.format(\"Failed to get dependencies for spec %s\", spec), e);\n      }","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/ExpansionService.java#L319-L355","documentation":"For schema-based (external configuration) transforms, ExpansionService.getTransform() parses the spec payload into a config object via transformBuilder.buildExternal(payloadToConfig(...)); any failure is rethrown as this RuntimeException with the spec and original message. It indicates the external config could not be parsed or the builder rejected it.","triggerScenarios":"Calling getTransform on a FunctionSpec handled by a schema-based transform builder where ExternalConfigurationPayload parsing or payloadToConfig conversion throws (wrong schema, missing fields, reflective construction failure).","commonSituations":"Cross-language pipeline sending config values that do not match the Java config class schema; extra/missing parameters in the external payload; type mismatches (string vs int) after schema evolution.","solutions":["Inspect the 'Caused by' to see whether parsing or buildExternal failed","Compare the payload schema against the Java configuration class's registered schema","Update the calling side to send exactly the fields the config class declares","Rebuild/redeploy the expansion service if the config class changed recently"],"exampleFix":"// before: external payload with unexpected field type\n{'retries': 'three'}\n// after\n{'retries': 3}","handlingStrategy":"validation","validationCode":"// validate payload fields against the Java config class schema before expansion\nSchema configSchema = SchemaRegistry.createDefault().getSchema(ConfigClass.class);\nif (!configSchema.getFieldNames().equals(sentFieldNames)) throw new IllegalArgumentException(\"payload schema mismatch\");","typeGuard":null,"tryCatchPattern":"try { transform = service.getTransform(spec, options); } catch (RuntimeException e) { if (e.getMessage().startsWith(\"Failed to build transform from spec\")) { /* reconcile payload schema with config class */ } throw e; }","preventionTips":["Send only fields the Java config class declares, with matching types","Register schemas for config classes with @DefaultSchema","Test cross-language expansion in CI after any schema change"],"tags":["java","beam","expansion-service","external-config","schema"],"backgroundTag":"schema-validation-failed","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"}