gchq/CyberChef · error · DishError

Data is not a valid ${Dish.enumLookup(type)}: ${sample}

Error message

Data is not a valid ${Dish.enumLookup(type)}: ${sample}

What it means

Thrown by Dish.set(value, type) after the value and type are assigned, when this.valid() returns false. valid() is a runtime type-check that asserts the JS value matches the declared Dish enum: STRING/HTML require typeof 'string', NUMBER requires typeof 'number', ARRAY_BUFFER requires an ArrayBuffer instance, BIG_NUMBER requires a BigNumber (or its serialised {c,e,s} form), FILE requires a File, LIST_FILE requires an Array of Files, JSON always passes. The sample is a truncated JSON.stringify of the offending value.

Source

Thrown at src/core/Dish.mjs:180

     * Sets the data value and type and then validates them.
     *
     * @param {*} value
     *     - The value of the input data.
     * @param {number} type
     *     - The data type of value, see Dish enums.
     */
    set(value, type) {
        if (typeof type === "string") {
            type = Dish.typeEnum(type);
        }

        log.debug("Dish type: " + Dish.enumLookup(type));
        this.value = value;
        this.type = type;

        if (!this.valid()) {
            const sample = Utils.truncate(JSON.stringify(this.value), 25);
            throw new DishError(`Data is not a valid ${Dish.enumLookup(type)}: ${sample}`);
        }
    }

    /**
     * Returns the Dish as the given type, without mutating the original dish.
     *
     * If running in a browser, get is asynchronous.
     *
     * @Node
     *
     * @param {number} type - The data type of value, see Dish enums.
     * @returns {Dish | Promise} - (Browser) A promise | (Node) value of dish in given type
     */
    presentAs(type) {
        const clone = this.clone();
        return clone.get(type);
    }

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Inspect the sample in the message: it shows the actual value. Reconcile the value's JS type with the Dish type enum you passed.
  2. If the value is a string but the dish is NUMBER/ARRAY_BUFFER/FILE, convert it first (parseFloat, new Uint8Array, new File) before calling set.
  3. For File/ListFile/ArrayBuffer reconstructed after IPC or structuredClone, rebuild the typed object: new File([buf], name), buf.slice(0) for ArrayBuffer.
  4. For BigNumber received as {c,e,s}, valid() already auto-converts it - if conversion fails, the object shape was wrong; reconstruct with new BigNumber(...).
  5. Confirm the type argument: pass a Dish enum constant (Dish.STRING) or a string name handled by Dish.typeEnum; never an unrelated integer.

Example fix

// before
const dish = new Dish();
dish.set("42", Dish.NUMBER); // throws: string is not a number

// after
const dish = new Dish();
dish.set(parseFloat("42"), Dish.NUMBER);
Defensive patterns

Strategy: type-guard

Validate before calling

function dishValueOk(value, typeEnum) {
  switch (typeEnum) {
    case 1: case 3: return typeof value === 'string';        // STRING, HTML
    case 2: return typeof value === 'number' && !isNaN(value); // NUMBER
    case 4: return value instanceof ArrayBuffer;               // ARRAY_BUFFER
    case 8: return typeof value === 'object' && value !== null; // JSON (always)
    case 6: return typeof File !== 'undefined' && value instanceof File; // FILE
    case 7: return Array.isArray(value) && value.every(f => f instanceof File); // LIST_FILE
    default: return true; // BYTE_ARRAY/JSON etc.
  }
}
// call before dish.set(value, typeEnum)

Type guard

function isDishString(v): v is string { return typeof v === 'string'; }
function isDishNumber(v): v is number { return typeof v === 'number' && !isNaN(v); }
function isDishArrayBuffer(v): v is ArrayBuffer { return v instanceof ArrayBuffer; }

Try / catch

try {
  dish.set(value, type);
} catch (e) {
  if (e instanceof DishError && /is not a valid/.test(e.message)) {
    // value/type mismatch - reconcile before retrying
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling dish.set('hello', Dish.NUMBER) (string value for a number dish); dish.set({}, Dish.ARRAY_BUFFER) (plain object, not ArrayBuffer); dish.set([72,73], Dish.FILE) (byte array where a File is required); passing a serialised File object that lost its File prototype after structuredClone/postMessage into Dish.FILE.

Common situations: An operation's run() returns a runtime value whose JS type disagrees with its declared output dish; round-tripping dishes through WebWorkers or Node IPC where File/ArrayBuffer/BigNumber lose their prototype; BigNumber passed as a plain JSON object from an external source; mistyping the type argument (e.g. passing the string 'number' when an enum was expected - though typeEnum handles the string form, a wrong enum int slips through).

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/de542db2ea9e9f9d. Report an issue: GitHub.