Packages
ash_typescript
0.17.1
0.17.3
0.17.2
0.17.1
0.17.0
0.16.0
0.15.3
0.15.2
retired
0.15.1
retired
0.15.0
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
retired
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.2
0.10.1
0.10.0
0.9.1
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.0
0.3.3
0.3.2
0.3.1
0.2.0
0.1.2
0.1.0
Generate type-safe TypeScript clients directly from your Ash resources and actions, ensuring end-to-end type safety between your backend and frontend.
Current section
Files
Jump to
Current section
Files
documentation/reference/troubleshooting.md
<!--
SPDX-FileCopyrightText: 2025 Torkild G. Kjevik
SPDX-FileCopyrightText: 2025 ash_typescript contributors <https://github.com/ash-project/ash_typescript/graphs/contributors>
SPDX-License-Identifier: MIT
-->
# Troubleshooting
This guide covers common issues you may encounter when using AshTypescript and how to resolve them.
## Common Issues
### TypeScript Compilation Errors
**Symptoms:**
- Generated types don't compile
- TypeScript compiler errors in generated files
- Missing type definitions
**Solutions:**
- Ensure generated types are up to date: `mix ash_typescript.codegen`
- Check that all referenced resources are properly configured
- Verify that all attributes are marked as `public? true`
- Check that relationships are properly defined
- Validate TypeScript compilation: `cd assets/js && npx tsc --noEmit`
### RPC Endpoint Errors
**Symptoms:**
- 404 errors when calling RPC endpoints
- Actions not found
- Endpoint routing issues
**Solutions:**
- Verify RPC controller and routes are configured:
```elixir
# router.ex
scope "/rpc", MyAppWeb do
pipe_through :api
post "/run", RpcController, :run
post "/validate", RpcController, :validate
end
```
- Ensure RPC controller exists and calls the `run_action` function from the Rpc module
- Check that actions are properly exposed in domain RPC configuration
- Ensure the domain is properly configured with the Rpc extension
- Verify action names match between domain configuration and TypeScript calls
- Check that endpoint paths in config match your router (default: `/rpc/run`, `/rpc/validate`)
### Type Inference Issues
**Symptoms:**
- Types show as `unknown` or `any`
- Field selection not properly typed
- Missing fields in type definitions
**Solutions:**
- Ensure all attributes are marked as `public? true`
- Check that relationships are properly defined
- Verify schema key generation and field classification
- Check `__type` metadata in generated schemas
- Ensure resource schema structure matches expected format
### Invalid Field Name Errors
AshTypescript validates that all field names are valid TypeScript identifiers.
#### Error: "Invalid field names found"
**Cause:** Resource attributes or action arguments use invalid TypeScript patterns:
- Underscore before digit: `field_1`, `address_line_2`
- Question mark suffix: `is_active?`, `verified?`
**Solution:** Add `field_names` or `argument_names` mapping in your resource's `typescript` block:
```elixir
defmodule MyApp.Task do
use Ash.Resource
typescript do
field_names [
field_1: "field1",
is_active?: "isActive"
]
argument_names [
some_action: [field_2: "field2"]
]
end
end
```
#### Error: "Invalid field names in map/keyword/tuple"
**Cause:** Map constraints or tuple type definitions contain invalid TypeScript field names.
**Solution:** Create a custom `Ash.Type.NewType` with `typescript_field_names/0` callback:
```elixir
defmodule MyApp.Types.CustomMap do
use Ash.Type.NewType,
subtype_of: :map,
constraints: [
fields: [
field_1: [type: :string],
is_valid?: [type: :boolean]
]
]
def typescript_field_names do
[
field_1: "field1",
is_valid?: "isValid"
]
end
end
```
### Metadata Field Errors
#### Error: "Invalid metadata field name"
**Cause:** Action metadata fields use invalid TypeScript patterns.
**Solution:** Use `metadata_field_names` DSL option in `rpc_action`:
```elixir
defmodule MyApp.Domain do
use Ash.Domain, extensions: [AshTypescript.Rpc]
typescript_rpc do
resource MyApp.Task do
rpc_action :read_tasks, :read do
metadata_field_names [
field_1: "field1",
is_cached?: "isCached"
]
end
end
end
end
```
#### Error: "Metadata field conflicts with resource field"
**Cause:** A metadata field has the same name as a resource attribute or calculation.
**Solution:** Either:
- Rename the metadata field in the action
- Use `metadata_field_names` to map to a different TypeScript name
- Use `show_metadata` to exclude the conflicting field
### Environment and Configuration Errors
#### Error: "No domains found"
**Cause:** Running codegen in wrong environment (dev instead of test).
**Solution:** Always use test environment for development:
```bash
# ✅ Correct
mix test.codegen
# ❌ Wrong
mix ash_typescript.codegen # Runs in dev environment
```
**Why:** Test resources (`AshTypescript.Test.*`) only compile in `:test` environment.
#### Error: "Module not loaded"
**Cause:** Test resources not compiled in current environment.
**Solution:** Ensure you're using test environment:
```bash
mix test.codegen
mix test
```
### Field Selection Issues
**Symptoms:**
- Field selection not working as expected
- Missing fields in results
- Type errors with field selection
**Solutions:**
- Use unified field format: `["field", {"relation": ["field"]}]`
- Verify calculation is properly configured and public
- Debug with RequestedFieldsProcessor if needed
- Check for invalid field format or pipeline issues
### Embedded Resources
#### Error: "should not be listed in domain"
**Cause:** Embedded resource incorrectly added to domain resources list.
**Solution:** Remove embedded resource from domain - embedded resources should not be listed in domain resources.
#### Type Detection Failure
**Cause:** Embedded resource not properly defined.
**Solution:** Ensure embedded resource uses `Ash.Resource` with proper attributes and the `embedded?: true` option.
### Union Types
**Symptoms:**
- Field selection failing for union types
- Type inference problems
- Unknown types for union members
**Solutions:**
- Use proper union member selection format: `{content: ["field1", {"nested": ["field2"]}]}`
- Check union storage mode configuration
- Verify all union member resources are properly defined
### Lifecycle Hooks
#### Custom Headers Getting Lost
**Wrong:**
```typescript
// ❌ Custom headers get replaced by config.headers
return {
headers: { ...config.headers, 'X-Custom': 'value' },
...config // config.headers completely replaces the headers object above
};
```
**Correct:**
```typescript
// ✅ Merge custom headers with existing headers
return {
...config,
headers: { 'X-Custom': 'value', ...config.headers } // Caller's headers override our defaults
};
```
#### Performance Timing Not Working
**Wrong:**
```typescript
// ❌ Context is read-only, modifications lost
export function beforeRequest(actionName: string, config: ActionConfig): ActionConfig {
const ctx = config.hookCtx;
ctx.startTime = Date.now(); // Lost!
return config;
}
```
**Correct:**
```typescript
// ✅ Return modified context
export function beforeRequest(actionName: string, config: ActionConfig): ActionConfig {
const ctx = config.hookCtx || {};
return {
...config,
hookCtx: { ...ctx, startTime: Date.now() }
};
}
```
#### Hook Not Executing
**Checklist:**
- Verify hook functions are exported from the configured module
- Check that `import_into_generated` includes the hooks module
- Regenerate types with `mix ash.codegen --dev`
- Ensure hook function names match the configuration exactly
- For channel hooks: Verify that `generate_phx_channel_rpc_actions: true` is set in config
#### TypeScript Errors with Hook Context
**Wrong:**
```typescript
// ❌ Type assertion without null check
const ctx = config.hookCtx as ActionHookContext;
ctx.trackPerformance; // Error if hookCtx is undefined
```
**Correct:**
```typescript
// ✅ Optional chaining or type guard
const ctx = config.hookCtx as ActionHookContext | undefined;
if (ctx?.trackPerformance) {
// Safe to use
}
```
### Typed Controller Issues
#### Error: "Controller 422 error"
**Cause:** Missing required argument or invalid type in request.
**Solution:** Check your request includes all required arguments (`allow_nil?: false`) and that values match expected types:
```elixir
# This argument is required — omitting it from the request body returns 422
argument :code, :string, allow_nil?: false
```
The error response includes all validation failures at once:
```json
{
"errors": [
{ "field": "code", "message": "is required" },
{ "field": "count", "message": "is invalid" }
]
}
```
#### Error: "Route handler must return %Plug.Conn{}"
**Cause:** Your route handler returned something other than a `%Plug.Conn{}` struct.
**Solution:** Ensure every code path in your handler returns `%Plug.Conn{}`:
```elixir
# ❌ Wrong — returns a tuple
run fn conn, params ->
{:ok, "result"}
end
# ✅ Correct — returns conn
run fn conn, params ->
Plug.Conn.send_resp(conn, 200, "OK")
end
```
#### Routes Not Generated
**Cause:** Missing configuration.
**Solution:** All three settings must be configured:
```elixir
config :ash_typescript,
typed_controllers: [MyApp.Session], # Required
router: MyAppWeb.Router, # Required
routes_output_file: "assets/js/routes.ts" # Required
```
#### Multi-Mount Ambiguity Error
**Cause:** A controller action is mounted at multiple paths without unique `as:` options.
**Solution:** Add `as:` to each scope:
```elixir
# ❌ Wrong — ambiguous
scope "/admin" do
get "/auth", SessionController, :auth
end
scope "/app" do
get "/auth", SessionController, :auth
end
# ✅ Correct — disambiguated
scope "/admin", as: :admin do
get "/auth", SessionController, :auth
end
scope "/app", as: :app do
get "/auth", SessionController, :auth
end
```
#### Path Parameter Missing Argument Error
**Cause:** Router path has a `:param` that doesn't have a matching DSL argument.
**Solution:** Add the missing argument:
```elixir
# Router: patch "/providers/:provider", SessionController, :update_provider
patch :update_provider do
argument :provider, :string # Must match :provider in the path
argument :enabled, :boolean, allow_nil?: false
run fn conn, params -> handle_update(conn, params) end
end
```
#### Error: "path parameter arguments with `allow_nil?: true`"
**Cause:** A path parameter argument has `allow_nil?: true` (the default), but it is always present in the router path at every mount. Path parameters are always provided by the router and can never be nil.
**Solution:** Set `allow_nil?: false` on the argument:
```elixir
# ❌ Wrong — :provider is always a path param
argument :provider, :string # allow_nil?: true (default) is wrong here
# ✅ Correct
argument :provider, :string, allow_nil?: false
```
#### Error: "path parameter arguments with `allow_nil?: false`"
**Cause:** A path parameter argument has `allow_nil?: false`, but it is only a path parameter at some mounts and will be nil at others (multi-mount scenario).
**Solution:** Set `allow_nil?: true` (the default) on the argument:
```elixir
# Route mounted at both /admin/pages/:id and /app/pages (no :id)
# :id is sometimes nil, so it must allow nil
# ❌ Wrong
argument :id, :string, allow_nil?: false
# ✅ Correct
argument :id, :string # allow_nil?: true (default) is correct here
```
#### Error Handler Not Transforming Errors
**Cause:** Error handler returning wrong type or nil unexpectedly.
**Solution:** Ensure your handler returns error maps (or nil to suppress):
```elixir
# MFA style
config :ash_typescript,
typed_controller_error_handler: {MyApp.ErrorHandler, :handle, []}
# The function receives (error_map, context_map)
defmodule MyApp.ErrorHandler do
def handle(error, %{route: route_name, source_module: _module}) do
# Return modified error map, or nil to suppress
Map.put(error, :route, route_name)
end
end
```
#### Typed Controller Hook Not Executing
**Checklist:**
- Verify `typed_controller_before_request_hook` or `typed_controller_after_request_hook` is configured
- Check that `typed_controller_import_into_generated` includes the hooks module
- Regenerate types with `mix ash_typescript.codegen`
- Ensure hook function names match the configuration exactly
- Verify hook functions are exported from the configured module
### Channel Hook Issues
#### Setting Default Timeout
Both patterns work for setting a default that the caller can override:
```typescript
// Option 1: Spread overwrites earlier properties
return {
timeout: 10000, // Default
...config // Caller's timeout (if set) overwrites
};
// Option 2: Explicit nullish coalescing
return {
...config,
timeout: config.timeout ?? 10000
};
```
If you want to **force** a timeout that cannot be overridden:
```typescript
return {
...config,
timeout: 10000 // Always 10000, ignores caller's value
};
```
#### Response Type Not Being Handled
**Solution:** Handle all three response types:
```typescript
export async function afterChannelResponse(
actionName: string,
responseType: "ok" | "error" | "timeout",
data: any,
config: ActionChannelConfig
): Promise<void> {
switch (responseType) {
case "ok":
// Handle success
break;
case "error":
// Handle error
break;
case "timeout":
// Handle timeout
break;
}
}
```
## Debug Commands
### Check Generated Output Without Writing
```bash
mix ash_typescript.codegen --dry-run
```
### Validate TypeScript Compilation
```bash
cd assets/js && npx tsc --noEmit
```
### Check for Updates
```bash
mix ash_typescript.codegen --check
```
### Clean Rebuild
If you're experiencing persistent issues:
```bash
mix clean
mix deps.compile
mix compile
mix test.codegen
```
### Validate Generated Types (Development)
When working on AshTypescript itself:
```bash
# Generate test types
mix test.codegen
# Validate TypeScript compilation
cd test/ts && npm run compileGenerated
# Test valid patterns compile
npm run compileShouldPass
# Test invalid patterns fail (must fail!)
npm run compileShouldFail
# Run Elixir tests
mix test
```
## Getting Help
If you're still experiencing issues:
1. **Check the documentation**: [hexdocs.pm/ash_typescript](https://hexdocs.pm/ash_typescript)
2. **Review the demo app**: [AshTypescript Demo](https://github.com/ChristianAlexander/ash_typescript_demo)
3. **Search existing issues**: [GitHub Issues](https://github.com/ash-project/ash_typescript/issues)
4. **Ask for help**: [GitHub Discussions](https://github.com/ash-project/ash_typescript/discussions)
5. **Join the community**: [Ash Framework Discord](https://discord.gg/ash-framework)
When reporting issues, please include:
- AshTypescript version
- Ash version
- Elixir version
- Error messages and stack traces
- Minimal reproduction example if possible