{"record":{"id":"523baf46ffa99662","repo":"apache/beam","slug":"query-project-cannot-be-empty","errorCode":null,"errorMessage":"query.project cannot be empty","messagePattern":"query\\.project cannot be empty","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/gcp/datastore/v1new/datastoreio.py","lineNumber":126,"sourceCode":"  _NUM_QUERY_SPLITS_MIN = 12\n  # Default bundle size of 64MB.\n  _DEFAULT_BUNDLE_SIZE_BYTES = 64 * 1024 * 1024\n\n  def __init__(self, query, num_splits=0):\n    \"\"\"Initialize the `ReadFromDatastore` transform.\n\n    This transform outputs elements of type\n    :class:`~apache_beam.io.gcp.datastore.v1new.types.Entity`.\n\n    Args:\n      query: (:class:`~apache_beam.io.gcp.datastore.v1new.types.Query`) query\n        used to fetch entities.\n      num_splits: (:class:`int`) (optional) Number of splits for the query.\n    \"\"\"\n    super().__init__()\n\n    if not query.project:\n      raise ValueError(\"query.project cannot be empty\")\n    if not query:\n      raise ValueError(\"query cannot be empty\")\n    if num_splits < 0:\n      raise ValueError(\"num_splits must be greater than or equal 0\")\n\n    self._project = query.project\n    # using _namespace conflicts with DisplayData._namespace\n    self._datastore_namespace = query.namespace\n    self._query = query\n    self._num_splits = num_splits\n\n  def expand(self, pcoll):\n    # This is a composite transform involves the following:\n    #   1. Create a singleton of the user provided `query` and apply a ``ParDo``\n    #   that splits the query into `num_splits` queries if possible.\n    #\n    #   If the value of `num_splits` is 0, the number of splits will be\n    #   computed dynamically based on the size of the data for the `query`.","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/gcp/datastore/v1new/datastoreio.py#L108-L144","documentation":"ReadFromDatastore's __init__ validates the query and raises ValueError when query.project is empty/None. The project id is required to talk to Cloud Datastore, so a query without it cannot be executed.","triggerScenarios":"Constructing a datastore.Query without setting project; passing a Query built where project was left as None by default; programmatically building queries where the project variable was an empty string.","commonSituations":"Config-driven pipelines where the GCP project env var is unset; reusing a Query object across projects and clearing fields; copy-pasted code omitting the project argument.","solutions":["Set project when constructing the query: Query(project='my-project', kind='MyKind').","Pass project explicitly to ReadFromDatastore/Query from a validated config value.","Check that the environment variable or config supplying the project id is populated before building the query."],"exampleFix":"// before\nquery = Query(kind='Person')  # project missing\nReadFromDatastore(query=query)\n\n// after\nquery = Query(project='my-gcp-project', kind='Person')\nReadFromDatastore(query=query)","handlingStrategy":"validation","validationCode":"if not query.project:\n    raise ValueError('set query.project before ReadFromDatastore')","typeGuard":"def has_project(query):\n    return bool(getattr(query, 'project', None))","tryCatchPattern":"try:\n    read = ReadFromDatastore(query=query, num_splits=n)\nexcept ValueError as e:\n    if 'query.project' in str(e):\n        query = Query(project=get_default_project(), kind=query.kind)\n        read = ReadFromDatastore(query=query, num_splits=n)\n    else:\n        raise","preventionTips":["Always pass project explicitly when constructing datastore.Query.","Validate the project id comes from a populated env var/config before pipeline construction.","Avoid building Query objects with all-default fields."],"tags":["python","apache-beam","datastore","gcp","validation"],"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-14T11:17:12.474Z"}