Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Troubleshooting — Metadata validation · Boson Protocol
Skip to content

Metadata validation

Symptom

{
  "valid": false,
  "errors": [
    { "path": "/productV1/title", "message": "required" },
    { "path": "/productV1/images/0/url", "message": "must match format" }
  ]
}

Or the on-chain createOffer reverts with an opaque "metadata hash mismatch" or similar.

Causes

1. Schema mismatch

You're using PRODUCT_V1 fields with a BASE schema (or vice versa). Check type on the top-level metadata object.

2. Required field missing

The error path tells you where. Look at the corresponding zod schema in @bosonprotocol/metadata — every field is required unless explicitly optional.

3. URL format issues

Image / file URLs must be:

  • HTTPS (https://...), or
  • IPFS (ipfs://Qm...).

http:// is rejected. Some clients also reject data URLs and relative paths.

4. UUID format

uuid must be a v4 UUID string (the crypto.randomUUID() output). Random strings won't pass.

5. Length overflow

Metadata is capped at 20 MB. If you embed images in dataUrl form, you'll blow this. Use CDN URLs or IPFS references for images.

6. Metadata-hash mismatch on-chain

If validate_metadata passes but createOffer reverts, your metadataHash doesn't match what metadataUri resolves to. The simplest fix is to derive the hash from the URI you got back from storeMetadata — the IPFS CID is the hash:

const metadataUri = await sdk.storeMetadata(metadata)
const metadataHash = metadataUri.replace(/^ipfs:\/\//, "")
// pass both into createOffer

Debugging

Always run validate_metadata before storeMetadata. Iterate until clean, then pin. This saves wasted IPFS writes.

const { valid, errors } = await sdk.validateMetadata(metadata)
if (!valid) { console.error(errors); process.exit(1) }
const uri = await sdk.storeMetadata(metadata)

Schema source

Related