can1357/oh-my-pi · error · OmpTypeError

cannot apply int to ${schema.ir.k}

Error message

cannot apply int to ${schema.ir.k}

What it means

`.int()` constrains a number schema to integers, so it throws when called on a schema whose IR kind is not "number". The message interpolates the actual kind. Thrown from `int()` at packages/omptype/src/zod.ts:160.

Source

Thrown at packages/omptype/src/zod.ts:160

			}
			throw new OmpTypeError(`cannot apply min to ${ir.k}`);
		},
		max(bound: number): ZodLikeSchema<Out> {
			const ir = schema.ir;
			if (ir.k === "string" || ir.k === "array") {
				lengthBound("max", schema, bound);
				const max = ir.max === undefined ? bound : Math.min(ir.max, bound);
				return next(restrictBase(schema, { ...ir, max }));
			}
			if (ir.k === "number") {
				if (Number.isNaN(bound)) throw new OmpTypeError("number max must not be NaN");
				if (ir.max !== undefined && ir.max <= bound) return next(restrictBase(schema, ir));
				return next(restrictBase(schema, { ...ir, max: bound, xmax: false }));
			}
			throw new OmpTypeError(`cannot apply max to ${ir.k}`);
		},
		int(): ZodLikeSchema<Out> {
			if (schema.ir.k !== "number") throw new OmpTypeError(`cannot apply int to ${schema.ir.k}`);
			return next(restrictBase(schema, { ...schema.ir, int: true }));
		},
		positive(): ZodLikeSchema<Out> {
			if (schema.ir.k !== "number") throw new OmpTypeError(`cannot apply positive to ${schema.ir.k}`);
			const ir = schema.ir;
			if (ir.min !== undefined && ir.min > 0) return next(restrictBase(schema, ir));
			return next(restrictBase(schema, { ...ir, min: 0, xmin: true }));
		},
		nonnegative(): ZodLikeSchema<Out> {
			if (schema.ir.k !== "number") throw new OmpTypeError(`cannot apply nonnegative to ${schema.ir.k}`);
			return this.min(0);
		},
		regex(expression: RegExp, message?: string): ZodLikeSchema<Out> {
			if (schema.ir.k !== "string") throw new OmpTypeError(`cannot apply regex to ${schema.ir.k}`);
			const expectation = message ?? `matching ${expression}`;
			const narrowed = schema.narrow((value, ctx) => {
				expression.lastIndex = 0;
				const matches = expression.test(value as string);

View on GitHub (pinned to 9690622007)

Solutions

  1. Call .int() only on t.number() schemas
  2. If the value is a numeric string, parse it: t.string().transform(...) or switch the field to t.number().int()
  3. Restructure the chain so .int() sits directly after t.number()

Example fix

// before
t.string().int()
// after
t.number().int()
Defensive patterns

Strategy: type-guard

Validate before calling

function canApplyInt(schema: ZodLikeSchema<unknown>): boolean {
  return schema.ir.k === "number";
}
if (!canApplyInt(schema)) throw new Error("int() requires a number schema");

Type guard

function isNumberSchema(ir: { k: string }): ir is { k: "number" } {
  return ir.k === "number";
}

Try / catch

try {
  schema = base.int();
} catch (err) {
  if (err instanceof OmpTypeError && err.message.startsWith("cannot apply int")) {
    throw new Error("field must be t.number() to use .int()");
  } else throw err;
}

Prevention

When it happens

Trigger: `t.string().int()`, `t.boolean().int()`, or `.int()` chained onto any non-number schema.

Common situations: Renaming/refactoring a field from number to string but keeping the `.int()` call; building schemas generically and mis-targeting the integer constraint; misremembering that omptype has no separate integer type (int is a number modifier).

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/189c27a238d01841. Report an issue: GitHub.