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.
null and assigning an After Effects object to it later.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"); // correctOptional 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:
| Rejected | Use instead |
|---|---|
async / await, Promise | Nothing. Every After Effects call already returns synchronously. |
Generators, timers, fetch, require | Not available inside After Effects |
Map, Set, Symbol, Proxy | A plain object, or an array |
class ... extends, get/set accessors | A plain function or object |
console.log | Return values in your result envelope |
Object.assign | Object 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" → invalidlayer.property("Position").setValue(pos); // pass the array itselfIf 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.
Related
- After Effects quirks: behaviours of After Effects itself that look like Prism problems.
- Known issues: open problems and their workarounds.
- Troubleshooting: connection checks.
Prism cannot reach After Effects
What to do when the Prism panel is open and connected but every request fails. Covers jsx-engine-unavailable, host-not-loaded, host-not-readable, host-missing, host-stale and engine-unreachable.
After Effects quirks
Behaviours of After Effects itself that look like Prism failing: locked layers, temporal ease array sizes, match names, parenting time compensation, time remap keys, text stroke, and fonts.