Skip to content

Fix Composer 404 on minified metadata and add debug logging#178

Open
philippdieter wants to merge 1 commit into
git-pkgs:mainfrom
philippdieter:main
Open

Fix Composer 404 on minified metadata and add debug logging#178
philippdieter wants to merge 1 commit into
git-pkgs:mainfrom
philippdieter:main

Conversation

@philippdieter

Copy link
Copy Markdown

Summary

Two issues are fixed in internal/handler/composer.go:

  1. 404 on package download — The download handler did not expand Composer v2
    minified metadata, so versions that inherit their dist field from a
    previous entry appeared to have no download URL and returned 404.
  2. No debug output with -log-level debug — The download/metadata code path
    contained zero Debug()-level log statements, so the log output was identical
    at info and debug levels.

Problem 1: 404 on package download

Symptoms

composer require neos/error-messages 8.3.19 fails with:

The "http://<proxy>/composer/files/neos/error-messages/8.3.19/55f2cdbcf6aca28d8026558215191c07a12b739e.zip"
file could not be downloaded (HTTP/1.1 404 Not Found)

Other packages download fine. The metadata endpoint (/composer/p2/...) works
correctly and returns the expected rewritten dist URL to Composer.

Root cause

Packagist serves package metadata in minified Composer v2 format
("minified": "composer/2.0"). In this format, each version entry only
contains fields that differ from the previous entry; omitted fields are
inherited. For example, version 8.3.19 of neos/error-messages has this raw
entry in the upstream metadata:

{
  "version": "8.3.19",
  "version_normalized": "8.3.19.0",
  "support": {
    "source": "https://github.com/neos/error-messages/tree/8.4.3"
  }
}

No dist field — it inherits dist from an earlier entry in the chain.

The codebase has two code paths that consume this metadata:

Code path Purpose Expands minified?
handlePackageMetadatarewriteMetadataexpandMinifiedVersions Serves metadata to Composer clients (rewrites dist URLs) Yes
handleDownloadfindDownloadURLFromMetadatafindDownloadURL Resolves the real download URL to fetch the zip No

Because findDownloadURLFromMetadata did not expand minified metadata, it
called findDownloadURL, which checks vmap["dist"] directly. For version
8.3.19 that field was nil, so the lookup returned an empty string and
handleDownload returned 404 at line 334.

Why other packages work

Packages whose metadata is not minified, or where every version entry happens
to include its own dist field, are unaffected. The bug only surfaces for
packages where the specific requested version inherits dist from a previous
entry in the minified chain.

Fix

In findDownloadURLFromMetadata, after decoding the upstream metadata JSON,
check for "minified": "composer/2.0" and call the existing
expandMinifiedVersions() on each package's version list before passing the
metadata to findDownloadURL. This reuses the same expansion logic that
rewriteMetadata already used correctly.

if metadata["minified"] == "composer/2.0" {
    if packages, ok := metadata["packages"].(map[string]any); ok {
        for pkgName, versions := range packages {
            versionList, ok := versions.([]any)
            if !ok {
                continue
            }
            packages[pkgName] = expandMinifiedVersions(versionList)
        }
    }
}

Problem 2: No debug output with -log-level debug

Symptoms

Running the proxy with -log-level debug produces the same output as
-log-level info. No debug-level lines appear.

Root cause

The logger was correctly configured at slog.LevelDebug — the flag parsing and
setupLogger / parseLogLevel functions work correctly. The problem was that
the download and metadata resolution code path contained no Debug()-level
log statements at all
. All logging in the critical path used Info() or
Error():

Location Level Message
composer.go handleDownload Info "composer download request"
composer.go handlePackageMetadata Info "composer metadata request"
composer.go handleDownload Error "failed to fetch metadata"
middleware.go LoggerMiddleware Info "request" (every HTTP request)

The only Debug() calls in the codebase were in proxyUpstream (search/list
endpoints) and ProxyUpstream — neither hit during a package download.

Fix

Added Debug()-level log statements throughout the download resolution path:

  • handleDownload: logs the metadata URLs being tried and the final
    resolved download URL (or "not found" if all sources were exhausted).
  • findDownloadURLFromMetadata: logs the upstream metadata URL being
    fetched, the HTTP response status code, whether minified expansion was
    applied, and the resulting download URL (or empty string).

Example debug output after the fix:

level=DEBUG msg="resolving download URL" package=neos/error-messages version=8.3.19 metadata_urls="[https://repo.packagist.org/p2/neos/error-messages.json https://repo.packagist.org/p2/neos/error-messages~dev.json]"
level=DEBUG msg="fetching upstream metadata for download lookup" url=https://repo.packagist.org/p2/neos/error-messages.json package=neos/error-messages version=8.3.19
level=DEBUG msg="upstream metadata response" url=https://repo.packagist.org/p2/neos/error-messages.json status=200
level=DEBUG msg="expanding minified metadata" url=https://repo.packagist.org/p2/neos/error-messages.json
level=DEBUG msg="download URL lookup result" url=https://repo.packagist.org/p2/neos/error-messages.json package=neos/error-messages version=8.3.19 download_url=https://api.github.com/repos/neos/error-messages/zipball/55f2cdbcf6aca28d8026558215191c07a12b739e
level=DEBUG msg="resolved download URL" package=neos/error-messages version=8.3.19 download_url=https://api.github.com/repos/neos/error-messages/zipball/55f2cdbcf6aca28d8026558215191c07a12b739e

Files changed

  • internal/handler/composer.go

Verification

  1. Rebuilt the proxy: go build -o proxy ./cmd/proxy
  2. Started the proxy: ./proxy -listen 0.0.0.0:9898 -base-url http://localhost:9898 -log-level debug
  3. Confirmed debug-level log lines now appear in the output.
  4. Ran composer require neos/error-messages 8.3.19 against the proxy —
    previously returned 404, now downloads and installs successfully (HTTP 200).

Authorship disclosure

This problem diagnosis and code fix were produced with the assistance of an
AI assistant (opencode / glm-5.1). The changes were verified by running the
existing test suite (go test ./... — 700 passed) and by reproducing the
original failure and confirming the fix end-to-end with composer require.

- Expand minified Composer v2 metadata in findDownloadURLFromMetadata
  so versions that inherit dist from a previous entry resolve correctly
- Add Debug()-level log statements in the download resolution path
  (handleDownload, findDownloadURLFromMetadata) so -log-level debug
  produces meaningful output
@andrew andrew added the bug Something isn't working label Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants