router-for-me/CLIProxyAPI · error

artifact exceeds declared size

Error message

artifact exceeds declared size

What it means

Client.DownloadArtifact enforces the artifact's declared Size as a cap: it passes maxSize to the HTTP getter (which limits the read) and then re-checks that len(data) does not exceed it. 'artifact exceeds declared size' means the downloaded payload was larger than the size published in the plugin manifest — the download is rejected rather than trusted.

Source

Thrown at internal/pluginstore/direct.go:40

	}
	return Artifact{}, fmt.Errorf("artifact not found for %s/%s", goos, goarch)
}

func (c Client) DownloadArtifact(ctx context.Context, artifact Artifact) ([]byte, error) {
	artifact = NormalizeInstallPlan(InstallPlan{Type: InstallTypeDirect, Artifacts: []Artifact{artifact}}).Artifacts[0]
	if errValidate := ValidateArtifact(artifact); errValidate != nil {
		return nil, errValidate
	}
	maxSize := int64(0)
	if artifact.Size > 0 {
		maxSize = artifact.Size
	}
	data, errDownload := c.get(ctx, artifact.URL, "application/octet-stream", RequestKindArtifact, maxSize)
	if errDownload != nil {
		return nil, errDownload
	}
	if maxSize > 0 && int64(len(data)) > maxSize {
		return nil, fmt.Errorf("artifact exceeds declared size")
	}
	return data, nil
}

func VerifyArtifactChecksum(artifact Artifact, data []byte) error {
	expected := strings.ToLower(strings.TrimSpace(artifact.SHA256))
	if expected == "" {
		return fmt.Errorf("artifact checksum missing")
	}
	actualBytes := sha256.Sum256(data)
	actual := hex.EncodeToString(actualBytes[:])
	if actual != expected {
		return fmt.Errorf("artifact checksum mismatch")
	}
	return nil
}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Refresh the plugin index/manifest so artifact.Size matches the currently published binary.
  2. If you publish the plugin, regenerate the manifest (size + sha256) on every release.
  3. Check what the URL actually serves (curl -L the artifact URL and compare Content-Length) to spot redirect/wrapping issues.
  4. Remove a stale zero/wrong Size only if you are certain the size is unknown — note Size == 0 disables the cap entirely.

Example fix

// before
// manifest stale: size: 1200000 but binary is now 1350000 bytes
artifact, data, err := fetchAndDownload(plan) // 'artifact exceeds declared size'

// after
// regenerate manifest from the actual release assets:
//   size: 1350000
//   sha256: <new digest>
artifact, data, err := fetchAndDownload(plan)
Defensive patterns

Strategy: validation

Validate before calling

if artifact.Size > 0 {
    log.Debugf("expecting ~%d bytes for %s", artifact.Size, artifact.Name)
}

Try / catch

data, err := client.DownloadArtifact(ctx, artifact)
if err != nil {
    if strings.Contains(err.Error(), "exceeds declared size") {
        return fmt.Errorf("manifest is stale for %s — refresh the plugin index", artifact.Name)
    }
    return err
}

Prevention

When it happens

Trigger: DownloadArtifact succeeds at the HTTP layer but returns more bytes than artifact.Size (only possible when Size > 0). Typically the server ignored the Range/limit semantics, the manifest's size field is stale, or the URL was redirected to a larger file (e.g. an HTML sign-in page or a newer build).

Common situations: Manifest size field not regenerated after a plugin rebuild; a proxy or artifact registry wrapping the binary (adding headers/HTML); downloading from a URL that now serves a different, larger asset.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/89c9b37200aae162. Report an issue: GitHub.