Skip to content

Build fails due to OpenProcessing rate limits (429) #955

Description

@perminder-17

Most appropriate sections of the p5.js website?

Home

What is your operating system?

Linux

Web browser and version

Firefox

Actual Behavior

Our site build sometimes fails when pages fetch data from OpenProcessing. The API returns 429 Too Many Requests, which makes our code expect arrays/strings but get nothing, causing crashes.

  • CI builds fail randomly.
  • Unable to build the website's reference from the forked repo.

Here's the CI failure : #954 when I tried uploading images. You can see the errors in the PR https://github.com/processing/p5.js-website/actions/runs/17451097533/job/49557683435?pr=954

getSketch 2215521 429 Too Many Requests
Cannot read properties of undefined (reading 'toLowerCase')

Expected Behavior

There should be no crashes when OP returns 429 or bad JSON.

Steps to reproduce

No response

Would you like to work on the issue?

No, I am not very confident with typeScript and CI testings, but a possible solution would be (during tests and local builds, don’t call OpenProcessing at all)

Activity

  1. added
    CriticalHigh severity / time sensitive problem that takes higher priority.
    on Sep 4, 2025
  2. ksen0 commented on Sep 4, 2025

    @ksen0
    Member

    Thanks for logging this @perminder-17 (also cc @davepagurek since this maybe a repeat from this potentially related prior issue: #955)
    I've marked is as "Critical" because it blocks many outstanding PRs.

    I will investigate the following: (1) not doing excessive OP API calls in CI (just 1 confirm it works) and (2) ensure there's a reasonable fallback on the site itself.

  3. moved this to In Progress in p5.js docs & toolson Sep 4, 2025
  4. davepagurek commented on Sep 6, 2025

    @davepagurek
    Collaborator

    Based on the code in https://github.com/processing/p5.js-website/pull/838/files, it looks like it should only hit that error if we're trying to load a sketch that's not in one of our default curations which we load in bulk once. It looks like this could happen if:

    • We are calling it with different params so it's not cached. Looks like we always call with the same params though.
    • Something about memoize isn't working, e.g. we're building pages in parallel where it used to be serial and the separate processes aren't using the same cache. We could try having a manual build script that pulls the data and writes the result to a json file that we check into git, so that we aren't constantly querying OP on every build
    • We're requesting a sketch that isn't in a curation (not sure where this would come from in our source code though)
    • Something changed on OP's side. Do we see the failures starting after a change on our end?

    I don't know what the specific issue is, but the second bullet would probably address it regardless if we make querying OP a manual step. If we aren't sure what the cause is, that could be a way forward? e.g.:

    • Make a script that pulls all curation sketches + their source code into a big JSON file, e.g. npm run build:sketches
    • Check in initial results in git
    • Update code to read from that file rather than from a fetch result
    • Update our docs to say that when we want to update content from OP, we have to rerun the script
  5. junseok44 commented on Sep 8, 2025

    @junseok44
    Contributor

    The OpenProcessing API appears to have rate limiting for consecutive requests within a short time period.
    When I make several consecutive requests, I get this response:

    /GET https://openprocessing.org/api/curation/87649/sketches
    {
        "success": false,
        "message": "Our Replicant Detection Division specialist Deckard believes that you repeated this action too many times for a human. Please try again in 47 seconds.",
        "object": null,
        "code": 429,
        "level": "info",
        "status": 429
    }
    

    After debugging, I found that the 429 errors are coming from the individual sketch API calls in the getSketch() function.
    This part was being called for almost every sketch page, which means that memoizedSketch isn't working.

    // check for sketch data in Open Processing API
    const response = await fetch(`${openProcessingEndpoint}sketch/${id}`);
    if (!response.ok) {
    //log error instead of throwing error to not cache result in memoize
    console.error("getSketch", id, response.status, response.statusText);
    }
    const payload = await response.json();
    return payload as OpenProcessingSketchResponse;

    Even though we're fetching from the same getCurationSketches() source, it's not finding matches in memoizedSketch because there's a type mismatch: the visualID from OpenProcessing's getCurationSketches() items comes as a number type, but the id parameter passed to getSketch from SketchLayout is a string type.

    When I added this logging code and checked the types, I saw:

    export const getSketch = memoize(
      async (id: string): Promise<OpenProcessingSketchResponse> => {
        // check for memoized sketch in curation sketches
      const curationSketches = await getCurationSketches();
      console.log('parameter type:', typeof id);
      console.log('data type', typeof curationSketches[0].visualID);
      console.log('is same?', id === curationSketches[0].visualID);
    
    parameter type: string
    OP data type number
    is same? false
    

    So the issue was in the comparison part: const memoizedSketch = curationSketches.find((el) => el.visualID === id)
    I think This can be easily fixable with a simple type conversion to enable proper caching.

    Could you assign this issue to me? I'd like to solve it.

  6. perminder-17 commented on Sep 8, 2025

    @perminder-17
    ContributorAuthor

    Aah....you're correct. We are using string instead of using number so, el.visualID === id is always false. Cache will miss everytime. I was debugging it but didn't noticed we are using a number. Probably your solution should fix the issue. Thanks for catching this. I'll assign you, Note: That's a critical bug which blocks other PRs merging so has a higher priority.

    Thanks for debugging this.

  7. ksen0 commented on Sep 8, 2025

    @ksen0
    Member

    Thanks for the fix @junseok44, I've merged it. I agree with your suggestion for followup PRs, especially not just logging the error but more meaningfully excluding invalid IDs and ensuring fallback behaviors. Do you want to keep working on this?

  8. junseok44 commented on Sep 9, 2025

    @junseok44
    Contributor

    Thanks! I'd like to continue working on this.
    I believe excluding invalid IDs during static page generation (in getStaticPaths()) should solve most problems.
    Do you think we need to add any additional fallback behaviors beyond that?

  9. ksen0 commented on Sep 9, 2025

    @ksen0
    Member

    Great, thanks for your work @junseok44 .

    I believe excluding invalid IDs during static page generation (in getStaticPaths()) should solve most problems.

    Yes, sounds good

    Do you think we need to add any additional fallback behaviors beyond that?

    I don't think so, but please check both website function and test behavior. Failing OP API calls should still result in failing tests.

    If you have any other ideas on improving tests / error logging, please feel free to do that. Some other optional thoughts: for example if the "rate limit" error is reached, then no further calls are made past the first failing one (not sure if this is already the behavior). Potentially, there should also be an automated check that caching is working / that not "too many" API calls are made, to prevent future regression? (When I was initially thinking about reducing number of calls / adding a fallback, it was more from the perspective of what to do if really too many calls are needed; it's great that there was a clear bugfix.) Those are all optional ideas, you're welcome to include what you think is reasonable in your PR.

    EDIT: "Critical" tag has been removed, since the time-sensitive part of this issue has been addressed.

  10. removed
    CriticalHigh severity / time sensitive problem that takes higher priority.
    on Sep 11, 2025
  11. junseok44 commented on Sep 12, 2025

    @junseok44
    Contributor

    I've worked on the error handling and test code for this PR.

    Currently, getCurationSketches() and getSketch() only use console.error when a fetch fails. However, I think it's better to explicitly throw Error to fail the build rather than returning invalid data that could cause build errors during processing.

    if(!response1.ok){ //log error instead of throwing error to not cache result in memoize
    console.error('getCurationSketches', response1.status, response1.statusText)
    }

    comment on this line mentioned using console.error instead of throw Error to prevent caching failed results, but since throw Error would fail the entire build anyway, i thought caching failed values wouldn't matter much.

    (While this shouldn't happen currently) For cases like getSketch() where individual pages might have cache misses and need to fetch data one by one, I was debating how to handle failures. For now, I decided to fail the entire build by throwing error in getSketch. but we could also make it skip just that specific page if needed.

    By the way, in our current CI/CD pipeline, the build runs independently from the tests. Since we're now testing whether the OP API is properly cached, shouldn't the build happen only after the tests pass?

  12. ksen0 commented on Sep 19, 2025

    @ksen0
    Member

    Thanks @junseok44 ! I'll close this as the linked PRs are closed.

  13. moved this from In Progress to Done in p5.js docs & toolson Sep 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

BugSomething isn't working

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions