You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Dyalog APL 20.0 throws error AC0040: could not fix function asynchronously when 2 ⎕FIX fails on invalid source inside a Jarvis HTTP request handler, and the code is in a ]link'd namespace.
The error is:
Category: "Object oriented programming", ENX 40
Fires asynchronously (different thread from the caller, ~0.5s delay)
Not catchable by :Trap 0 in the calling function
Not produced by any APL code in Link (confirmed by instrumentation)
]link.create stark /path/to/Stark/APLSource
]link.create repro /path/to/AC0040/APLSource
repro.Tests.RunTest 0
Expected output:
POST /upload →200
error AC0040: could not fix function
∧
Complete: 1 error.
Done
What the Repro Does
Two files:
Wrapper.aplc — A :Class that wraps Stark with one endpoint (POST /upload). The handler:
Parses the JSON body
Calls 2 tmpns.⎕FIX lines where lines is the submitted source (invalid APL)
Catches the expected ⎕FIX failure in :Trap 0
Returns a response
Tests/RunTest.aplf — Starts the server and sends a POST with source: 'this is not valid APL'.
Investigation Summary
Through binary search of a larger test function (178 lines), we isolated the trigger to a single operation: 2 ⎕FIX failing on invalid source inside a Jarvis HTTP thread.
The following do NOT trigger AC0040:
2 ⎕FIX failing in the main thread (same namespace, same invalid source)
2 ⎕FIX failing in a plain &-spawned thread
2 ⎕FIX failing in a class method on a &-spawned thread
2 ⎕FIX failing via 85⌶ + :Hold + :Trap 85 on a &-spawned thread
2 ⎕FIX failing in nested class threads (class method spawning handler thread)
2 ⎕FIX succeeding in a Jarvis HTTP thread (valid source)
Any Jarvis HTTP request that doesn't call ⎕FIX
Additionally:
File ties are not the cause — fires with -watch=ns on both links
Link APL code is not involved — OnAfterFix, Fix, and Notify were instrumented and never fire
The error is interpreter-internal — the "Complete: N error." format does not exist in any APL source
See WALKTHROUGH.md for the full bug report with detailed findings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 ⎕FIX failing on invalid source inside a Jarvis HTTP request handler produces an asynchronous error AC0040: could not fix function — but only when the code lives in a ]LINK'd namespace.
The error cannot be caught with :Trap. It fires on a different thread roughly half a second after the ⎕FIX failure. It is not generated by any APL code in Link, Stark, or Jarvis — it appears to originate from the interpreter itself.
Wrapper.aplc — A class with a single HTTP endpoint. The endpoint receives a JSON body, extracts a source field, and attempts 2 ⎕FIX on it. The ⎕FIX is wrapped in :Trap 0:
The ⎕FIX fails, :Trap 0 catches it, the endpoint returns a JSON error response, the test prints POST /upload →200 and finishes cleanly.
Actual
The endpoint handles the error correctly and returns 200. But roughly half a second later, this appears asynchronously in the session:
error AC0040: could not fix function
∧
Complete: 1 error.
This error is not catchable. It fires on a different thread. In a larger test suite, it can derail unrelated :Trap 0 blocks running at the time.
Isolation testing
Through systematic binary search of a larger function (178 lines) that originally triggered this, we isolated the trigger to a single operation: 2 ⎕FIX failing on invalid source inside a Jarvis HTTP request handler.
What triggers AC0040 and what doesn't
Scenario
AC0040?
2 ⎕FIX fails in a Jarvis thread, namespace is ]LINK'd
Yes — always
2 ⎕FIX fails in the main thread (same linked namespace, same invalid source)
No
2 ⎕FIX fails in a plain &-spawned thread (same linked namespace)
No
2 ⎕FIX fails in a class method on a &-spawned thread
No
2 ⎕FIX fails via 85⌶ (as Jarvis uses) on a &-spawned thread
No
2 ⎕FIX fails via 85⌶ + :Hold + :Trap 85 on a &-spawned thread
No
2 ⎕FIX fails in nested class threads (class method spawning handler thread)
No
2 ⎕FIXsucceeds in a Jarvis thread (valid source, linked namespace)
No
Any Jarvis request that doesn't call ⎕FIX (linked namespace)
No
]link.create with -watch=ns (no file ties) — 2 ⎕FIX fails in Jarvis thread
Yes
Both stark and repro linked with -watch=ns
Yes
In short: the error requires the intersection of linked namespace + Jarvis HTTP request processing + failed 2 ⎕FIX. We attempted to reproduce without Jarvis by replicating its ingredients (&-threads, class methods, 85⌶, :Hold, nested class threads) but could not trigger AC0040 outside the full Jarvis stack.
File ties are not the cause
Link's FixTie function ties APL objects to source files when watch≡'both' (the default). We tested with -watch=ns on both linked namespaces, which disables file tying entirely. AC0040 still fires. The link arrows confirm the change took effect (→ instead of ←→).
Link is not involved
We instrumented Link's three entry points by patching them at runtime to log calls:
⎕SE.Link.OnAfterFix — editor/afterfix callback
⎕SE.Link.Fix — the fix orchestrator
⎕SE.Link.Notify — file system watcher callback
All three were patched with ⎕← logging before the server started. The patches were confirmed successful (each ⎕FX returned the function name). None of them fired during the test — no >>> output appeared.
This proves AC0040 is not produced by any APL code in Link. Link's callbacks are completely uninvolved.
The error is interpreter-internal
The error format error AC0040: could not fix function + ∧ + Complete: 1 error. does not appear in any APL source we can search:
Not in Link source (~/dev/link/)
Not in Stark/Jarvis source
Not in Dyalog's bundled APL files (SALT/, workspace files)
The "Complete:" string does not appear in any .aplf, .aplc, .apln, or .dyalog file
The error code AC0040 maps to ⎕DMX.(Category ENX)≡'Object oriented programming' 40 in Dyalog's diagnostic table (SALT/spice/table.tsv).
This all points to the error being generated by the interpreter's internal C code — not by any APL-level callback, hook, or error handler.
What we think is happening
The Jarvis request-handling path involves Conga's event loop (LDRC.Wait), thread spawning from within class methods, and 85⌶ execution of handler functions. Something in this specific combination — which we could not replicate with any subset of these mechanisms — causes the interpreter to asynchronously attempt an internal ⎕FIX operation after the user-level 2 ⎕FIX fails. That internal operation fails with AC0040, which surfaces as an uncatchable session error.
Impact
The asynchronous error disrupts any code running under :Trap 0 at the time it fires. In the application where this was discovered (a game server with an API test suite), the AC0040 from a bot-upload validation endpoint would derail the test runner's error handling, producing misleading DOMAIN ERRORs instead of the actual test results.
A workaround exists (avoid calling 2 ⎕FIX for validation inside request handlers), but 2 ⎕FIX inside :Trap 0 should fail silently regardless of context.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters