Collection validators

What is a collection validator?

A collection validator is a rule that checks the whole selection of files at once. Use it when your logic depends on relationships between files rather than a single file.

  • If the selection breaks your rule, return an error object with a message users can see.
  • If everything is okay, return nothing and the selection is accepted.

Unlike file validators, collection validators are synchronous and there is no validation queue.

How it can be used

  • Prevent duplicates across the selection (by name, size, hash, or another stable key you compute).
  • Ensure uniform type across all files (for example, all entries share the same top-level MIME like image/* or application/*).
  • Cross-file dependencies (for example, if a CSV is present, a README must also be present).

What users will see

When the selection doesn’t meet your rule, the uploader shows a clear message explaining what to fix.

Validation model and signature

Collection validators are synchronous functions:

1type CollectionValidator = (
2 collection: OutputCollectionState,
3 api: UploaderPublicApi
4) => OutputErrorCollection | undefined;

See also: OutputCollectionState, UploaderPublicApi

Error type returned on failure:

1type OutputErrorCollection = {
2 message: string;
3 payload?: Record<string, unknown>;
4};

Here, payload is an optional object where you can include extra details about the error (for example, actual vs expected dimensions) and then catch them in your app via events or the API.

When it runs

Collection validators re-run on specific selection-related changes:

  • Triggers:
    • When files are added to or removed from the list
    • When any file’s errors list changes (for example, a file becomes valid/invalid after file-level validation, or uploading fails)
  • Not triggered: general file state changes (upload progress, post-upload edits, uploading success) unless they cause an errors change

Implications:

  • Do not rely on properties that appear only after upload (for example, fileInfo, cdnUrl, cdnUrlModifiers).
  • It’s fine to base collection rules on whether files passed/failed file validators by inspecting entry.errors.
  • Prefer rules that can be decided from information available at selection time (filenames, sizes, MIME types, or flags already present on entries).
  • If you need to validate post-upload information directly, use a file validator with an appropriate runOn and check the whole collection for custom errors there.

Examples

Specified mix of file types

1const specifiedMix: CollectionValidator = (collection, api) => {
2 const entries = collection.allEntries;
3 const hasCover = entries.some((e) =>
4 /cover\.(jpg|png|jpeg)$/i.test(e.fileName ?? "")
5 );
6 const galleryCount = entries.filter((e) =>
7 /gallery\.(jpg|png|jpeg)$/i.test(e.fileName ?? "")
8 ).length;
9 if (!hasCover || galleryCount < 3) {
10 return {
11 message:
12 "Please include one cover image and at least three gallery images",
13 };
14 }
15};
16
17const config = document.querySelector("uc-config");
18config.collectionValidators = [specifiedMix];

No duplicates in the selection

1const noDuplicates: CollectionValidator = (collection, api) => {
2 const seen = new Set<string>();
3 for (const e of collection.allEntries) {
4 const key = `${e.fileName?.toLowerCase()}::${e.size || 0}`;
5 if (seen.has(key)) {
6 return { message: "The selection contains duplicate files" };
7 }
8 seen.add(key);
9 }
10};
11
12const config = document.querySelector("uc-config");
13config.collectionValidators = [noDuplicates];

Uniform top-level MIME type

1const uniformTopLevelMime: CollectionValidator = (collection, api) => {
2 const top = (m: string) => m.split("/")[0] ?? "unknown";
3 const types = new Set(
4 collection.allEntries
5 .filter((e) => !!e.mimeType)
6 .map((e) => top(e.mimeType))
7 );
8 if (types.size > 1) {
9 return { message: "Please select files of the same top-level type" };
10 }
11};
12
13const config = document.querySelector("uc-config");
14config.collectionValidators = [uniformTopLevelMime];

CSV requires a README in the selection

1const csvRequiresReadme: CollectionValidator = (collection, api) => {
2 const hasCsv = collection.allEntries.some((e) =>
3 /\.csv$/i.test(e.fileName ?? "")
4 );
5 if (!hasCsv) return;
6 const hasReadme = collection.allEntries.some((e) =>
7 /README(\.[^.]+)?$/i.test(e.fileName ?? "")
8 );
9 if (!hasReadme) {
10 return {
11 message: "If a CSV is present, include a README in the selection",
12 };
13 }
14};
15
16const config = document.querySelector("uc-config");
17config.collectionValidators = [csvRequiresReadme];

Error localization

Show validation messages in the user’s language:

  • Single-language projects: return plain strings from your validators.
  • Multi-language projects: define localization keys, extend your locales, and reference those keys from validators.

Learn how to set up keys and extend locales: Localization

Best practices

  • Keep rules fast and deterministic; collection validators are synchronous.
  • Prefer clear, actionable messages so users know how to fix the selection.
  • Combine with file validators for per-file checks (dimensions, metadata) and use collection validators for cross-file logic (duplicates, uniform types, cross-file dependencies).