# Need to use module registry lock with \`read-language\`?

**URL:** <https://racket.discourse.group/t/need-to-use-module-registry-lock-with-read-language/4401>\
**Category:** General\
**Created:** [September 26, 2026, 7:48pm UTC](https://racket.discourse.group/t/need-to-use-module-registry-lock-with-read-language/4401 "2026-09-26T19:48:15Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [September 26, 2026, 7:48pm UTC](https://racket.discourse.group/t/need-to-use-module-registry-lock-with-read-language/4401/1 "2026-09-26T19:48:15Z")

</div>

I have a bug against Racket Mode that was very surprising and confusing to me: [#768](https://github.com/greghendershott/racket-mode/issues/768). A situation with many `instantiate-linklet: mismatch` errors in color-lexers.

I believe I finally boiled it down concurrency when using `read-language`, as well as calling the returned `get-info` procedure with e.g. a `color-lexer` key, which loads modules.

At first I fixed (?) this using a general purpose semaphore. Then I remembered something about a module registry lock, i.e. `namespace-call-with-registry-lock`, which also fixes it (AFAICT).

Here's a minimal-ish example:

```scheme
#lang racket/base

(define source "#lang rhombus\ndef value = 1\n")

(define (read-language-and-get-color-lexer)
  (define get-info (read-language (open-input-string source)))
  (get-info 'color-lexer #f))

(define (read-language-and-get-color-lexer/with-lock)
  (namespace-call-with-registry-lock (current-namespace)
                                     read-language-and-get-color-lexer))

;; Change this to see many errors, or not. Note that, after running
;; with #t, a given REPL session may produce errors even with
;; #f, until you refresh the session and get a new namespace.
(define want-to-see-many-instantiate-linklet-errors? #t) ;; <====

(for ([_ 5])
  (thread (if want-to-see-many-instantiate-linklet-errors?
              read-language-and-get-color-lexer
              read-language-and-get-color-lexer/with-lock)))
(sleep 1)

;; Background story:
;; https://github.com/greghendershott/racket-mode/issues/768

```

The concurrency vulnerable spot seems to be between calling `read-language` and calling the returned `get-info` procedure value -- another thread could muck with the namespace's module registry, there?

Beside sharing the experience, I guess my questions are:

1. Is this as-expected -- use of `read-language` by multiple threads should be guarded by the module registry lock? (Or, using a distinct `current-namespace` for each thread.) IOW does it sound like I finally arrived at the likely solution?

2. If so, should I do a doc PR for `read-language` to point this out, as a hint (or is that considered too obvious, and/or the consumers of this documentation too few, to make it worthwhile)?

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [September 27, 2026, 12:52am UTC](https://racket.discourse.group/t/need-to-use-module-registry-lock-with-read-language/4401/2 "2026-09-27T00:52:41Z")

</div>

I believe (after some AI-assisted investigation) that the calls to `dynamic-require` in the rhombus `get-info` code should use the registry lock themselves, along these lines: [Comparing racket:master...samth:get-info-registry-lock · racket/rhombus · GitHub](https://github.com/racket/rhombus/compare/master...samth:rhombus-prototype:get-info-registry-lock)

---

<div class="post-metadata">

**Author:** ![shhyou](https://avatars.discourse-cdn.com/v4/letter/s/ccd318/32.png) [@shhyou](https://racket.discourse.group/u/shhyou)\
**Post date:** [September 27, 2026, 10:27am UTC](https://racket.discourse.group/t/need-to-use-module-registry-lock-with-read-language/4401/3 "2026-09-27T10:27:45Z")

</div>

It's true that Rhombus uses `dynamic-require` in `get-info`, but Datalog, 2D Syntax, Algol 60 and Racklog all do this too. So it looks like not worrying about module registry in `get-info`s has become a convention.

---

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [September 27, 2026, 1:25pm UTC](https://racket.discourse.group/t/need-to-use-module-registry-lock-with-read-language/4401/4 "2026-09-27T13:25:52Z")

</div>

This FrosthavenManager commit using the registry lock may be of interest. I later was able to change strategies entirely (see the commits linked to the corresponding issue]([Is it possible to record AoE specs as dependencies of bestiaries? · Issue #108 · benknoble/frosthaven-manager · GitHub](https://github.com/benknoble/frosthaven-manager/issues/108)))), but I found using the registry lock to be important in multi-`thread`-ed code.

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [September 27, 2026, 2:21pm UTC](https://racket.discourse.group/t/need-to-use-module-registry-lock-with-read-language/4401/5 "2026-09-27T14:21:24Z")

</div>

I agree, and the docs actually suggest doing this without a lock: [17.3.5&nbsp;Source-Handling Configuration](https://docs.racket-lang.org/guide/language-get-info.html)

However, the docs for `dynamic-require` say that a lock is needed: "Beware that concurrent dynamic-requires in namespaces that share a module registry can create race conditions; see also namespace-call-with-registry-lock."
