Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

serve-instrument exits when an instrument directory is deleted or a request URL has a malformed percent-escape

Open
#1,804 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
82/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
node.js, typescript
Domain
backend, testing

Research direction

Start with packages/serve-instrument/src/server.tsx at the watcher callback, updateEncodedBundle, request handler, and URL decoding points named in the issue. Then read packages/serve-instrument/src/__tests__/server.test.ts and run the focused tests. Done when the deletion and malformed-URL cases return the expected responses without stopping the server or disrupting other instruments.

Written by the indexing model from the issue text.

Description

Area: Instruments Bug Difficulty: Low Good First Issue Priority: Low

serve-instrument exits with an unhandled error when an instrument directory is deleted or renamed while it runs, or when it receives a URL with a malformed percent-escape. In both cases an exception escapes an async function that is called with void: this.handler.handle(...) for requests, and this.updateEncodedBundle() in the fs.watch callback. Node turns the unhandled rejection into a process exit. In updateEncodedBundle, only the bundle() call is inside the try; the readdir/readFile before it are not. In --all mode, deleting or renaming one instrument folder kills the server for all the others, and so does a git checkout that removes one. An author has to notice that the terminal died and restart it.

Where

packages/serve-instrument/src/server.tsx:45-48, 62-79 and 243-247, 312:

    this.watcher = fs.watch(target, { recursive: false }, () => {
      // ...
      void this.updateEncodedBundle();
    });
// ...
  private async updateEncodedBundle(): Promise<void> {
    const inputs: BundlerInput[] = [];
    const filepaths = await fs.promises
      .readdir(this.target, 'utf-8')
      // ...
    for (const filepath of filepaths) {
      const loader = inferLoader(filepath);
      const content: string | Uint8Array = await fs.promises.readFile(filepath, /* ... */);
      // ...
    }
    const start = Date.now();
    try {
// ...
      const decodedName = decodeURIComponent(name!);
// ...
    this.server = http.createServer((...args) => void this.handler.handle(...args));

Reproduce

  1. Build it (pnpm --filter @opendatacapture/serve-instrument build) and run node dist/cli.js --all <dir> on a directory containing forms/FOO/index.ts and forms/BAR/index.ts.
  2. Open /forms/BAR, then rm -rf <dir>/forms/BAR.
    Actual: ↺ [forms/BAR] File changed, rebuilding..., then Error: ENOENT: no such file or directory, scandir '…/forms/BAR' and the process exits (verified on main). /forms/FOO is no longer served.
  3. Restart, then curl 'http://localhost:3000/forms/%E0%A4%A'.
    Actual: URIError: URI malformed at decodeURIComponent and the process exits (verified on main).

Expected: the server logs the failure and keeps running. A deleted instrument answers 404 and a malformed URL answers 400.

Tests

packages/serve-instrument/src/__tests__/server.test.ts:

  • it('should keep serving other instruments after an instrument directory is deleted, so a rebuild failure does not kill the server'): fire the captured watch callback after removing the temp directory, and assert that the remaining instrument still returns 200.
  • it('should answer 400 to a malformed percent-escape in an instrument URL rather than crashing')

No e2e test applies: serve-instrument is not part of the stack under testing/.

Suggested fix

Move the directory listing and file reads inside the existing try in updateEncodedBundle. Wrap handle in Server's request callback with a .catch that logs the error and ends the response with 500 if headers are not yet sent. Map a URIError from decodeURIComponent to 400.

Dominant language
TypeScript
Stars
119
Forks
19
Avg merge
1d 4h
Merged PRs (30d)
44

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from DouglasNeuroInformatics/OpenDataCapture

All issues in DouglasNeuroInformatics/OpenDataCapture

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.