Skip to content
Support

When Prism rejects your script

Why Prism rejects a script before it reaches After Effects, and the exact fix for each case: the TypeScript gate, the result envelope rule, banned constructs, and template-literal number errors.

Prism checks every script before it reaches After Effects. A rejected script never runs, so nothing in your project changed and nothing needs undoing.

The check exists because ExtendScript fails at run time with messages like undefined is not an object, pointing at a line of compiled output you never wrote. Catching it beforehand is worth the friction — but only when the message tells you what to change. This page covers each case.

The short version
A rejected script did not run. Your project is untouched.
Most rejections are one of four patterns, and each has a one-line fix.
The single most common: declaring a variable as null and assigning an After Effects object to it later.
Every script must END with a top-level JSON.stringify(...). One nested inside an if does not count.

The TypeScript gate

Script rejected: TypeScript gate: the script does not type-check against the AE + Prism SDK types.

Your script is checked against the real After Effects type definitions. These are the patterns that get rejected, and what to write instead.

let comp = null then assigned later — TS2322

The most frequent rejection by a wide margin.

// Rejected — TypeScript infers the type `null`
let comp = null;
for (let i = 1; i <= app.project.numItems; i++) {
  const it = app.project.item(i);
  if (it instanceof CompItem && it.name === "Main") comp = it;   // TS2322
}
// Works — declare what it can hold
let comp: CompItem | null = null;
for (let i = 1; i <= app.project.numItems; i++) {
  const it = app.project.item(i);
  if (it instanceof CompItem && it.name === "Main") comp = it as CompItem;
}

A text or footage method is "missing" — TS2339

prism.layer() returns the base Layer type, which does not carry TextLayer or AVLayer methods such as sourceRectAtTime.

// Rejected — sourceRectAtTime does not exist on Layer
const l = prism.layer(comp, "Title");
const box = l.sourceRectAtTime(0, false);        // TS2339
// Works — say which kind of layer it is
const l = prism.layer(comp, "Title") as TextLayer;
const box = l.sourceRectAtTime(0, false);

Passing a name where an object is expected — TS2345

prism.layer() takes the composition object, not its name.

const l = prism.layer("Main", "Title");          // TS2345
const l = prism.layer(comp, "Title");            // correct

Optional values that can be null

app.project.file, an optional stroke, a layer source — all can legitimately be null, and the gate will say so. Check before use, or assert when you know better:

const f = app.project.file;
const path = f ? f.fsName : "(unsaved project)";

The script produced no result

Script produced no result envelope (result is null).

Every script must end with a top-level JSON.stringify(...). A JSON.stringify inside an if, a try, or a loop is not the script's completion value, even when that branch runs.

// Returns null — the stringify is nested
if (comp) {
  JSON.stringify({ success: true, name: comp.name });
}
// Works — build inside, stringify at the top level
let out = { success: false, error: "no comp" };
if (comp) out = { success: true, name: comp.name };
JSON.stringify(out);

Constructs that cannot run in After Effects

Script rejected: async/await cannot run in After Effects — ExtendScript is fully synchronous.

After Effects has no event loop. These are rejected before they can fail confusingly at run time:

RejectedUse instead
async / await, PromiseNothing. Every After Effects call already returns synchronously.
Generators, timers, fetch, requireNot available inside After Effects
Map, Set, Symbol, ProxyA plain object, or an array
class ... extends, get/set accessorsA plain function or object
console.logReturn values in your result envelope
Object.assignObject spread: { ...a, ...b }

Modern syntax that does work: const/let, arrow functions, template literals, destructuring, spread, for...of, optional chaining, ??, plain classes, and TypeScript types.

"invalid numeric result (divide by zero?)"

This one is misleading — it is usually a template literal holding an array.

const pos = [960, 540];
layer.property("Position").setValue(`${pos}`);   // becomes "960,540" → invalid
layer.property("Position").setValue(pos);        // pass the array itself

If you are building a string for a numeric field, interpolate the elements, not the array.

Undo groups

Rejected: app.beginUndoGroup / app.endUndoGroup

Prism wraps every call in a single undo group so your whole request reverts in one step. Adding your own unbalances After Effects' stack and produces the warning "Undo Group mismatch. Will attempt fix." Name the group with the undoGroup argument instead.

Reading the error

Every runtime failure reports against your source, not the compiled output:

line: 14        sourceLine: 14
sourceText: const l = prism.layer(comp, "Nope");

sourceLine and sourceText point at what you wrote. If you see compiledLine, ignore it — it refers to Prism's internal output and is included only for our own debugging.