Cross-Platform Debugging
Systematic approach to debugging issues that only occur on Erlang OR JavaScript.
Quick Diagnosis
bash1# Run on both targets to identify which fails 2just test-erlang 3just test-js
Common Causes
1. FFI Implementation Mismatch
Symptom: Different behavior between targets for the same function.
Check:
bash1# Compare FFI implementations 2diff <(grep -A 20 "function_name" src/birch_ffi.erl) \ 3 <(grep -A 20 "function_name" src/birch_ffi.mjs)
Common issues:
- Return type mismatch (tuples vs arrays)
- Error handling differences
- String encoding (UTF-8 handling)
2. Platform-Specific APIs
Symptom: Function works on one platform, undefined/error on other.
JavaScript-only APIs:
process.stdout,process.stderr(Node.js)Deno.isatty()(Deno)console.logbehavior varies by runtime
Erlang-only APIs:
- Process dictionary (
erlang:put/get) - OTP behaviors (
gen_server, etc.) :loggerintegration
3. Async Behavior
Symptom: Race conditions or timing issues on JavaScript.
Check:
- Erlang is synchronous by default
- JavaScript may need
awaitor callbacks - Look for Promise handling in FFI
4. Type Coercion
Symptom: Unexpected values or type errors.
| Gleam Type | Erlang | JavaScript |
|---|---|---|
Int | Integer | Number |
Float | Float | Number |
String | Binary | String |
List | List | Array |
Tuple | Tuple | Array |
Nil | nil atom | undefined |
5. TTY/Terminal Detection
Symptom: Color output works on one platform.
Check:
gleam1// In platform.gleam 2is_stdout_tty() // Different implementation per platform
Debugging Steps
Step 1: Isolate the Failure
bash1# Run specific test 2gleam test --target erlang -- --filter "test_name" 3gleam test --target javascript -- --filter "test_name"
Step 2: Add Debug Output
gleam1// Temporary debug logging 2import gleam/io 3io.debug(value) // Works on both targets
Step 3: Check FFI
- Read
src/birch/internal/platform.gleamfor declarations - Compare
src/birch_ffi.erlandsrc/birch_ffi.mjs - Look for behavioral differences
Step 4: Test JavaScript Runtimes
bash1# Test on all JS runtimes 2just test-integration-node 3just test-integration-deno 4just test-integration-bun
Step 5: Check Runtime Detection
In birch_ffi.mjs, verify runtime detection:
javascript1// Node.js 2typeof process !== 'undefined' && process.versions?.node 3 4// Deno 5typeof Deno !== 'undefined' 6 7// Bun 8typeof Bun !== 'undefined' 9 10// Browser 11typeof window !== 'undefined'
FFI Debugging Checklist
- Both implementations exist for the function
- Return types match Gleam declaration
- Error cases handled identically
- Edge cases (empty string, null, special chars) tested
- All JS runtimes have fallbacks (Node, Deno, Bun, browser)
Quick Fixes
| Issue | Erlang Fix | JavaScript Fix |
|---|---|---|
| Undefined function | Check module exports | Check export statement |
| Wrong return type | Match Gleam type exactly | Return correct JS type |
| Encoding issues | Use unicode:characters_to_binary | Use TextEncoder |
| TTY detection | Check os:type() | Check process.stdout.isTTY |