{"id":"89c37a5287af958d","repo":"apache/kafka","slug":"unexpected-contents-in-the-artifact-exactly-one-v","errorCode":null,"errorMessage":"Unexpected contents in the artifact. Exactly one version directory is expected.","messagePattern":"Unexpected contents in the artifact\\. Exactly one version directory is expected\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"docker/extract_docker_official_image_artifact.py","lineNumber":58,"sourceCode":"def set_executable_permissions(directory):\n    for root, _, files in os.walk(directory):\n        for file in files:\n            path = os.path.join(root, file)\n            os.chmod(path, os.stat(path).st_mode | 0o111)\n\n\ndef extract_artifact(artifact_path):\n    docker_official_images_dir = Path(os.path.dirname(os.path.realpath(__file__)), \"docker_official_images\")\n    temp_dir = Path('temp_extracted')\n    try:\n        if temp_dir.exists():\n            shutil.rmtree(temp_dir)  \n        temp_dir.mkdir()\n        with zipfile.ZipFile(artifact_path, 'r') as zip_ref:\n            zip_ref.extractall(temp_dir)\n        artifact_version_dirs = list(temp_dir.iterdir())\n        if len(artifact_version_dirs) != 1:\n            raise Exception(\"Unexpected contents in the artifact. Exactly one version directory is expected.\")\n        artifact_version_dir = artifact_version_dirs[0]\n        target_version_dir =  Path(os.path.join(docker_official_images_dir, artifact_version_dir.name))\n        target_version_dir.mkdir(parents=True, exist_ok=True)\n        for image_type_dir in artifact_version_dir.iterdir():\n            target_image_type_dir = Path(os.path.join(target_version_dir, image_type_dir.name))\n            if target_image_type_dir.exists():\n                shutil.rmtree(target_image_type_dir)            \n            shutil.copytree(image_type_dir, target_image_type_dir)\n            set_executable_permissions(target_image_type_dir)\n    finally:\n        if temp_dir.exists():\n            shutil.rmtree(temp_dir)\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"--path_to_downloaded_artifact\", \"-artifact_path\", required=True,\n                        dest=\"artifact_path\", help=\"Path to zipped artifacy downloaded from github actions workflow.\")\n    args = parser.parse_args()","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/docker/extract_docker_official_image_artifact.py#L40-L76","documentation":"Raised by extract_artifact() in docker/extract_docker_official_image_artifact.py after unzipping a downloaded GitHub Actions artifact into a temp dir: the script expects exactly ONE top-level entry inside the zip (a single version directory). If iterdir() returns 0, 2, or more entries, the layout contract is broken and the script aborts rather than guessing which directory is canonical.","triggerScenarios":"Calling extract_artifact(artifact_path) where the zip's top level contains !=1 entries. Causes: zip created without the conventional '<version>/...' root (files at archive root, or nested under multiple dirs), an empty/corrupt artifact, or the wrong artifact downloaded from the workflow run.","commonSituations":"Artifact re-packaged by CI in a way that flattened the version directory, multiple version directories zipped together, hidden files (e.g. macOS __MACOSX, .DS_Store) counted by iterdir(), or operator downloaded the wrong workflow artifact.","solutions":["Inspect the zip layout: unzip -l <artifact_path> and confirm there is exactly one top-level directory named like a version.","If extra hidden entries (e.g. __MACOSX) are present, repackage the zip with only the version directory at root.","Re-download the artifact from the GitHub Actions run that produced the official image, and verify its checksum.","If the producer workflow changed its packaging, update that workflow to emit a single version-rooted zip."],"exampleFix":"# before (zip with files at root)\n$ unzip -l artifact.zip\n    Dockerfile\n    entrypoint.sh\n# after (zip with single version dir)\n$ unzip -l artifact.zip\n    3.7.0/Dockerfile\n    3.7.0/entrypoint.sh\n$ python docker/extract_docker_official_image_artifact.py --path_to_downloaded_artifact artifact.zip","handlingStrategy":"validation","validationCode":"# Inspect the artifact zip before extracting; require exactly one top-level version dir.\nimport zipfile, re, sys\ndef validate_artifact(artifact_path):\n    with zipfile.ZipFile(artifact_path) as z:\n        top = {n.split('/')[0] for n in z.namelist() if n}\n    invalid = [d for d in top if not re.match(r'^\\d+\\.\\d+\\.\\d+(\\.[^.]+)?$', d)]\n    if len(top) != 1 or invalid:\n        sys.exit(f\"Artifact must contain exactly one version directory, found: {sorted(top)}\")","typeGuard":"# True only when the zip contains a single top-level version-like directory.\ndef is_single_version_artifact(artifact_path) -> bool:\n    import zipfile, re\n    with zipfile.ZipFile(artifact_path) as z:\n        top = {n.split('/')[0] for n in z.namelist() if n}\n    return (len(top) == 1\n            and bool(re.match(r'^\\d+\\.\\d+\\.\\d+(\\.[^.]+)?$', next(iter(top)))))","tryCatchPattern":"from extract_docker_official_image_artifact import extract_artifact\ntry:\n    extract_artifact(artifact_path)\nexcept Exception as e:\n    if \"Exactly one version directory is expected\" in str(e):\n        # List top-level entries so the operator can fix/repack the zip.\n        import zipfile\n        with zipfile.ZipFile(artifact_path) as z:\n            print(\"Top-level entries:\", sorted({n.split('/')[0] for n in z.namelist()}))\n    raise","preventionTips":["Download the official image artifact from the canonical release location and verify its SHA512 before running extraction.","Open the zip locally and confirm it has one top-level directory named like the Kafka version (e.g. 3.7.0) before invoking the script.","Reject artifacts that bundle macOS metadata (__MACOSX) or extra top-level files; repack or re-download instead.","Keep extract_artifact idempotent: it already cleans 'temp_extracted', so a re-run after fixing the artifact is safe."],"tags":["python","docker","release-tooling","zip","validation"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}