GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Tar::getComposerJson ignores non-directory entries at archive root, leading to unwrapping failure during install · Issue #13232 · composer/composer

Tar::getComposerJson ignores non-directory entries at archive root, leading to unwrapping failure during install #13232

New issue
Copy link
New issue
Copy link
Open
Bug
#13233
Open
Tar::getComposerJson ignores non-directory entries at archive root, leading to unwrapping failure during install#13232
Bug
#13233
Copy link

Description

@VernSG
VernSG
opened on Nov 4, 2026
Issue body actions

My composer.json:

{
    "name": "my/project",
    "repositories": [
        {
            "type": "artifact",
            "url": "artifacts/"
        }
    ],
    "require": {
        "company/auth-sdk": "^1.0"
    }
}

Output of composer diagnose:

Checking Composer version: OK
Composer version: 2.11.999-dev+source
PHP version: 8.4.21
PHP binary path: /opt/homebrew/Cellar/[email protected]/8.4.21/bin/php
OpenSSL version: OpenSSL 3.6.2 7 Apr 2026
curl version: 8.20.0 libz 1.2.12 brotli brotli/1.2.0 zstd supported ssl OpenSSL/3.6.3 HTTP 1.0, 1.1, 2, 3
zip: extension present, unzip present, 7-Zip not available
Checking composer.json: OK
Checking platform settings: OK
Checking git settings: OK git version 2.39.5
Checking http connectivity to packagist: OK
Checking https connectivity to packagist: OK
Checking disk free space: OK

When I run this command:

composer install -vvv

I get the following output:

The package archive artifacts/company-auth-sdk-1.0.0.tar.gz contains a package directory auth-sdk/ alongside an incidental root file (such as README.md or LICENSE).

During repository initialization, ArtifactRepository inspects the archive via Composer\Util\Tar::getComposerJson() and outputs:

Loading composer repositories with package information
Found package company/auth-sdk (1.0.0) in file company-auth-sdk-1.0.0.tar.gz
...
Package operations: 1 install, 0 updates, 0 removals
Installs: company/auth-sdk:1.0.0
  - Downloading company/auth-sdk (1.0.0)
  - Installing company/auth-sdk (1.0.0): Extracting archive
Generating autoload files

The command finishes with exit code 0, but ArchiveDownloader fails to unwrap auth-sdk/ because of the top-level README.md. Inside vendor/company/auth-sdk/:

vendor/company/auth-sdk/
├── README.md
└── auth-sdk/
    ├── composer.json
    └── src/
        └── Client.php

Because composer.json and src/ remain nested in auth-sdk/ instead of the package root, running the project fails with a fatal error:

Fatal error: Uncaught Error: Class "Company\AuthSdk\Client" not found in ...

And I expected this to happen:

Composer\Util\Tar::getComposerJson() should exhibit parity with Composer\Util\Zip::locateFile and ArchiveDownloader:

  1. In Composer\Util\Zip::locateFile, any non-metadata root entry (file or directory) is tracked via $dirname === '.'. When an archive contains a top-level directory alongside a file and lacks a root composer.json, Zip correctly rejects it:
    RuntimeException: Archive has more than one top level directories, and no composer.json was found on the top level, so it's an invalid archive. Top level paths found were: README.md,auth-sdk/
    
  2. But in Composer\Util\Tar::extractComposerJsonFromFolder (src/Composer/Util/Tar.php:51), entries are filtered with if ($folderFile->isDir()). Non-directory entries at the root of a TAR archive are completely ignored.
  3. This creates a mismatch between archive discovery (Tar.php claims the package is wrapped in a single directory) and archive installation (ArchiveDownloader refuses to unwrap because sibling files exist), leading to broken autoloading.

Additionally, Tar::extractComposerJsonFromFolder should verify that composer.json is a file ($phar['composer.json']->isFile()) before calling getContent(), preventing BadMethodCallException if a directory is named composer.json.

Activity

  1. VernSG
    added the
    Bug
    issue type on Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Bug

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.