{"record":{"id":"108535e5f8cb9fa4","repo":"apache/beam","slug":"expansion-service-with-target-target-does-not-specify-any","errorCode":null,"errorMessage":"Expansion service with target '{target}' does not specify any default destinations.","messagePattern":"Expansion service with target '(.+?)' does not specify any default destinations\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/gen_xlang_wrappers.py","lineNumber":126,"sourceCode":"    - gradle_target: 'sdks:java:io:expansion-service:shadowJar'\n      destinations:\n        python: 'apache_beam/io'\n      skip_transforms:\n        - 'beam:schematransform:org.apache.beam:some_transform:v1'\n  \"\"\"\n  from apache_beam.transforms.external import BeamJarExpansionService\n  from apache_beam.transforms.external_transform_provider import ExternalTransform\n  from apache_beam.transforms.external_transform_provider import ExternalTransformProvider\n\n  transform_list: list[dict[str, Any]] = []\n\n  with open(input_services) as f:\n    services = yaml.safe_load(f)\n  for service in services:\n    target = service['gradle_target']\n\n    if \"destinations\" not in service:\n      raise ValueError(\n          f\"Expansion service with target '{target}' does not \"\n          \"specify any default destinations.\")\n    service_destinations: dict[str, str] = service['destinations']\n    for sdk, dest in service_destinations.items():\n      validate_sdks_destinations(sdk, dest, target)\n\n    transforms_to_skip = service.get('skip_transforms', [])\n\n    # use dynamic provider to discover and populate wrapper details\n    provider = ExternalTransformProvider(BeamJarExpansionService(target))\n    discovered: dict[str, ExternalTransform] = provider.get_all()\n    for identifier in sorted(discovered.keys()):\n      wrapper = discovered[identifier]\n      if identifier in transforms_to_skip:\n        continue\n\n      transform_destinations = service_destinations.copy()\n","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/gen_xlang_wrappers.py#L108-L144","documentation":"gen_xlang_wrappers.py reads the expansion-services YAML config and, for each service entry, requires a 'destinations' mapping of SDK to output directory. A service without that key cannot have wrappers generated, so generate_transforms_config raises ValueError naming the service's gradle target.","triggerScenarios":"An expansion service entry in the input services YAML lacks the required 'destinations' field while running the xlang wrapper generation script.","commonSituations":"Contributors registering a new expansion service forget to add default destinations; YAML restructuring accidentally drops the key.","solutions":["Add a 'destinations' mapping (SDK -> directory) to the offending service entry in the expansion services YAML.","Match the destinations format of existing entries and confirm each destination directory exists under sdks/python.","Re-run gen_xlang_wrappers.py."],"exampleFix":"// before (services yaml)\n- gradle_target: :sdks:java:io:expansion-service:shadowJar\n// after\n- gradle_target: :sdks:java:io:expansion-service:shadowJar\n  destinations:\n    python: sdks/python/apache_beam/transforms/xlang_io","handlingStrategy":"validation","validationCode":"for svc in yaml.safe_load(open(services_yaml)):\n    assert 'destinations' in svc, f\"service {svc.get('gradle_target')} needs a 'destinations' map\"","typeGuard":"def has_destinations(svc):\n    return isinstance(svc, dict) and isinstance(svc.get('destinations'), dict) and bool(svc['destinations'])","tryCatchPattern":"try:\n    generate_transforms_config(services_yaml, ...)\nexcept ValueError as e:\n    if 'does not specify any default destinations' in str(e):\n        print('Add destinations to the offending expansion service entry')","preventionTips":["Validate the services YAML schema in CI before running generation.","Copy the structure of existing service entries when registering new ones.","Keep a JSON schema for the expansion services config."],"tags":["yaml","code-generation","cross-language","missing-field"],"backgroundTag":"missing-required-config-field","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"}