Skip to content

p5.strands transpilation error gives no context about the callback #9317

Open

Description

@AdeshDeshmukh

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • WebGPU
  • p5.strands
  • Build process
  • Unit testing
  • Internationalization
  • Friendly errors
  • Other (specify if possible)

p5.js version

2.4.0-rc.1

Web browser and version

Chromium 153.0.8010.12, running p5.js 2.4.0-rc.1 from cdn.jsdelivr.net, which is the same build the p5.js Web Editor loads

Operating system

macOS

Steps to reproduce this

Steps:

  1. Open the p5.js Web Editor and start a new sketch.
  2. Paste the snippet below as-is. It is a complete sketch, nothing else is needed.
  3. Run the sketch and open the browser console.

Snippet:

function setup() {
  createCanvas(200, 200, WEBGL);
  const fn = () => {};
  buildMaterialShader(fn.bind(null));
}

Console output

🌸 p5.js says: p5.strands shaders are experimental, so functions for building shaders and the hooks available within them may change in future versions. You can get involved by giving feedback to help direct its development! For more info, see https://p5js.org/contribute/p5.strands/
Uncaught (in promise) SyntaxError: Unexpected token (1:23)

Captured in Chromium 153 against the same p5@2.4.0-rc.1 build the Web Editor loads, from a local page. Running it in the Web Editor gives the same two lines.

What I expected

One legible error that names the problem in my callback and points at it, the way the rest of the friendly error system does.

What actually happened

A raw acorn SyntaxError with no mention of p5.strands and no pointer to the callback. The stack the browser shows is ten frames of acorn internals, so it does not even show which p5 function was involved. Setting Error.stackTraceLimit = 100 shows the rest of the chain:

at parse (p5.js:82651)
at transpileStrandsToJS (p5.js:114210)
at p5.Shader.modify (p5.js:116671)
at fn.buildMaterialShader (p5.js:58459)

The line numbers above are from the published 2.4.0-rc.1 bundle. In the source tree this is the parse() call inside transpileStrandsToJS(), in src/strands/strands_transpiler.js (around line 2116).

The cause is that p5.strands rebuilds the callback from its source text, and the source of a bound function is function () { [native code] }, which is not valid JavaScript. The failure happens inside acorn's parse(), before buildStrandsCallback() is reached, so none of the strands error handling runs and the user is left with an acorn error that mentions neither p5.strands nor their callback.

A callback source that is not valid JavaScript fails the same way:

function setup() {
  createCanvas(200, 200, WEBGL);
  buildMaterialShader('void main(){}');
}
Uncaught (in promise) SyntaxError: Unexpected token (1:12)

Possible approach

  1. Wrap the parse() call in transpileStrandsToJS() so a syntax error in the callback source becomes a strands friendly error instead of escaping as a raw acorn SyntaxError. The message should say that the callback source could not be parsed, and show the offending position, e.g. Unexpected token (1:23).
  2. Detect the case where the callback source is not usable at all, such as a bound function, whose toString() is function () { [native code] }, and say that directly, since no amount of position information helps there.
  3. Leave the two paths in [p5.js 2.0+ Bug Report] : p5.strands error paths dump internals to console before throwing #9310 unchanged, so this can be a separate change.

Happy to fix this myself once an approach is agreed on.

Related issues

I did not want to reopen #9310 for this, since it looks like a separate failure mode, but happy to fold it in if that is easier.

Scope

This one is entirely inside p5.strands, in src/strands/strands_transpiler.js. I am happy to work on it, and happy to pair with @subhranshudash13-dotcom, who offered to pick up the strands side of #9310. I can also see @LalitNarayanYadav working on #9218 and @harshiltewari2004 on #9252, so I would rather not step on either of you, happy to coordinate.

There is a related problem in the friendly error system's parameter validator, where the message comes out empty and the raw Zod error object is logged for callback parameters. That one is outside p5.strands, and it may already be covered by #9209, so I will look into it separately rather than file it right away.

Activity

  1. welcome commented on Oct 22, 2026

    @welcome

    Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, please make sure to fill out the inputs in the issue forms.

    For guidance on contributing, check out our contributing guidelines and other resources for contributors.
    💬 If you have questions or need support, feel free to join the Processing Foundation Forum or visit our Community page.
    📜 Please also review our Code of Conduct to understand our community standards.
    Thank You!

  2. davepagurek commented on Oct 23, 2026

    @davepagurek
    Contributor

    Agreed that we should have a more helpful error here. We possibly can try to handle all the cases you mention? e.g. we could have a special error when we see [native code] in the stringification to give more specific guidance ("did you use .bind(...) on a function?") as well as just providing a clearer error (ideally with a line number) when there's a syntax problem.

  3. AdeshDeshmukh commented on Oct 23, 2026

    @AdeshDeshmukh
    Author

    I'm happy to take this on. Here's the approach I'm thinking of:

    1. Detect bound functions before parsing — check if the callback's stringified source contains [native code] (which happens with .bind(...)). If so, throw a direct, user-friendly error like "did you use .bind(...) on a function?" since no line number helps there.

    2. Wrap parse() in transpileStrandsToJS() — catch any SyntaxError from acorn and re-throw it as a strands-friendly error that includes the line and column position so the user can find the typo in their callback.

    3. Leave valid callbacks untouched — no console dumps, no behavior change for working code.

    Does this match what you had in mind? I'll wait for your thumbs-up before writing any code.

  4. AdeshDeshmukh commented on Oct 23, 2026

    @AdeshDeshmukh
    Author

    I have a question regarding the error style for this..!

    For these two cases — the bound-function check and the wrapped parse() error — should the errors route through strands_FES (userError/internalError) like the other p5.strands errors, or should they be plain thrown Errors?
    I want to match the existing error style in the codebase so it feels consistent for users.

    I would like to have your opinion on this.!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions