decentraland / decentraland/builder

Strip directory entries and 0-byte files from representations[].contents at deploy time

Open
#3,388 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
156
Forks
91
Avg merge
2d 7h
Merged PRs (30d)
31

Description

## Problem

When a curator deploys a wearable collection, the Catalyst content-validator rejects the entity with:

```
Deploy failed with status 400: Representation content: 'male/bin/' is not one of the content files
```

This happens because `item.data.representations[].contents` may contain:
- **Directory entries** (e.g. `male/bin/`) — introduced by the zip parser in `builder-client`
- **0-byte files** — silently dropped from the entity content payload by `makeContentFiles` in `src/modules/deployment/contentUtils.ts`, but still listed in the metadata

The metadata and the content payload fall out of sync, and the Catalyst validator catches the mismatch on every deploy attempt.

## Root cause

In `src/modules/deployment/contentUtils.ts`, `makeContentFiles` intentionally skips 0-byte blobs:

```ts
const isEmpty = files[fileName] instanceof Blob && files[fileName].size === 0
if (FILE_NAME_BLACKLIST.includes(fileName) || isEmpty) continue
```

However, `buildWearableEntityMetadata` copies `item.data.representations` as-is without applying the same filter. This means any file skipped by `makeContentFiles` is still present in the entity metadata — causing the Catalyst validator to reject the deploy.

## Proposed fix

In `buildItemEntityBlobs` (or `buildItemEntity`), strip directory entries and 0-byte entries from `representations[].contents` before building the entity metadata:

```ts
const filteredRepresentations = representations.map(rep => ({
...rep,
contents: rep.contents.filter(name => {
if (name.endsWith('/')) return false // skip directory entries
const blob = contentFiles[name]
if (blob instanceof Blob && blob.size === 0) return false // skip 0-byte
return true
})
}))
```

This ensures the metadata passed to `buildEntity` stays in sync with the content payload, regardless of what is stored in the Builder API.

## Why this fix is needed even after fixing builder-client

The upstream fix in `decentraland/builder-client` (filtering at zip extraction time) will prevent new items from being stored with bad data. But items *already stored* in the Builder API with directory entries or 0-byte entries in their `representations[].contents` will continue to fail on deploy without this defensive fix.

## Related

- Upstream fix: decentraland/builder-client#79

Requested by Rocío Corral Mena via Slack

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.