can1357/oh-my-pi · error · OmpTypeError
pipe operands must be functions or Types
Error message
pipe operands must be functions or Types
What it means
`type.pipe(...)` accepts only functions and Types as operands. When an operand is neither a Type (handled above) nor a function, the pipeline builder throws 'pipe operands must be functions or Types' as an OmpTypeError, because there is no way to turn it into a step.
Source
Thrown at packages/omptype/src/type.ts:1339
if (
!forcePipeline &&
schema[kSteps].length === 0 &&
!target.hasSteps &&
!hasMorph(schema.ir) &&
!hasMorph(target.ir)
) {
schema = makeType(intersect(schema.ir, target.ir), [], metaOf(schema));
continue;
}
const out = target.opaqueOutput ? undefined : (target.stepOut ?? target.ir);
schema = makeType(
schema.ir,
[...schema[kSteps], { kind: "pipe", fn: value => target.run(value), out, try: catchErrors }],
metaOf(schema),
);
continue;
}
if (typeof candidate !== "function") throw new OmpTypeError("pipe operands must be functions or Types");
schema = makeType(
schema.ir,
[...schema[kSteps], { kind: "pipe", fn: candidate as Step["fn"], try: catchErrors }],
metaOf(schema),
);
}
return inheritScope(source, schema);
}
function projectIO(ir: IR, io: "in" | "out"): IR {
switch (ir.k) {
case "morph":
return projectIO(io === "in" || ir.out === undefined ? ir.input : ir.out, io);
case "sub":
if (io === "out" && ir.schema.opaqueOutput) return { k: "unknown" };
return projectIO(io === "out" ? (ir.schema.stepOut ?? ir.schema.ir) : ir.schema.ir, io);
case "array":
return { ...ir, el: projectIO(ir.el, io) };View on GitHub (pinned to 9690622007)
Solutions
- Pass an actual function: `type('string').pipe(s => s.trim())`.
- Pass a Type created by omptype: `.pipe(otherType)`.
- Check for undefined operands from import cycles or missing arguments; log the operand before piping.
- If piping into another library's validator, wrap it: `.pipe(v => otherValidator.parse(v))`.
Example fix
// before
type('string').pipe(someValidator); // plain object, throws
// after
type('string').pipe(v => someValidator.parse(v)); Defensive patterns
Strategy: validation
Validate before calling
const operands = [step1, step2];
for (const op of operands) {
if (typeof op !== 'function' && !(op instanceof OmpType)) {
throw new Error(`bad pipe operand: ${String(op)}`);
}
}
type('string').pipe(...operands); Type guard
function isPipeOperand(op) {
return typeof op === 'function' || op instanceof OmpType;
} Try / catch
try {
const T = base.pipe(...steps);
} catch (e) {
if (e instanceof OmpTypeError && e.message.includes('pipe operands')) {
// filter steps: steps.filter(isPipeOperand) and retry
} else throw e;
} Prevention
- Type step arrays as `(fn | Type)[]` so bad operands fail at compile time.
- Beware circular imports that turn transform functions into `undefined` at call time.
- Wrap third-party validators in a function before piping.
When it happens
Trigger: `type('string').pipe(42)`, `.pipe(undefined)` (e.g. an optional callback not provided), passing a plain object or string where a transform was intended, or a mis-imported identifier that is undefined at runtime.
Common situations: Circular-import shadowing making a transform function undefined; passing a schema-like object from another library expecting auto-conversion; typos in the transform function reference.
Related errors
- cannot apply divisibility to ${this.ir.k}
- Invalid pattern: {err}
- broken pipe
- No messages to continue from
- Cannot continue from message role: assistant
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/36b4d03cbcf1f479.
Report an issue: GitHub.