Action failed: c:myComponent$controller$myAction [<JS error message>]
An Aura component's client-side JavaScript controller threw an exception. The error message is wrapped in `Action failed: c:component$controller$method` for the framework, but the *interesting* part is the inner JS error. Look at the bracketed message, not the prefix.
Also seen asAction failed: c:·controller error aura·Action failed: c:myComponent$controller·Aura Action failed
A user clicks a button in an Aura component and the screen shows a red banner: Action failed: c:opportunityForecast$controller$calculateRevenue [Cannot read property 'value' of undefined]. The framework wraps the actual JavaScript error in its own diagnostic format. The first part names the component and method; the bracketed second part is the real cause.
How to read the message
The Aura framework's error format follows a consistent shape:
Action failed: c:<componentName>$<entity>$<methodName> [<JavaScript error>]
Three pieces:
c:componentNameidentifies the component's namespace and name.c:is the default for unmanaged components.$controller$methodNameidentifies the controller method where the error occurred. (For helpers, it's$helper$methodName.)- The bracketed message is the actual JavaScript error, the part you actually need to debug.
The wrapper exists because Aura serializes errors across the framework's client-server boundary; the wrapping preserves diagnostic context even if the error originates deep in handler chains.
The broken example
A controller method that accesses a property without checking:
({
calculateRevenue: function(component, event, helper) {
var account = component.get('v.selectedAccount');
// Throws if selectedAccount is null or undefined
var revenue = account.value;
component.set('v.calculatedRevenue', revenue * 1.2);
}
})
If selectedAccount is null (e.g., the user hasn't selected one yet), account.value throws Cannot read property 'value' of undefined. The framework wraps it and presents the action-failed message.
The fix: defensive reads + structured error handling
({
calculateRevenue: function(component, event, helper) {
var account = component.get('v.selectedAccount');
if (!account || !account.value) {
component.set('v.errorMessage', 'Please select an account first.');
return;
}
try {
var revenue = account.value;
component.set('v.calculatedRevenue', revenue * 1.2);
} catch (e) {
console.error('Revenue calculation failed:', e);
component.set('v.errorMessage', 'Could not calculate revenue: ' + e.message);
}
}
})
The defensive read prevents the most common cause. The try/catch provides a fallback when something genuinely unexpected fires.
The fixed example, end to end
A complete controller pattern with structured error handling:
// opportunityForecastController.js
({
calculateRevenue: function(component, event, helper) {
helper.safelyExecute(component, function() {
var account = component.get('v.selectedAccount');
if (!account || !account.value) {
throw new Error('No account selected');
}
var rate = component.get('v.growthRate') || 1.2;
var revenue = account.value * rate;
component.set('v.calculatedRevenue', revenue);
});
}
});
// opportunityForecastHelper.js
({
safelyExecute: function(component, fn) {
try {
fn();
component.set('v.errorMessage', null);
} catch (e) {
console.error('Action error:', e);
component.set('v.errorMessage', e.message || 'An unexpected error occurred');
}
}
});
The helper wraps controller logic so every action gets uniform error handling. The user sees a clear message; the developer gets a console log; the component continues to work after the error.
Common causes and their fixes
Aura action errors usually fall into a few categories:
Cannot read property X of undefined. A reference is null/undefined when you accessed a property. Add a null check.
Apex callout returned an error. The action called an Apex method that threw. Check the Apex side; the error message often contains the Apex AuraHandledException body.
Storage exceeded for cache. The Aura framework's client-side storage filled up. Reduce cache usage in your controller; the platform limits per-component storage.
Action not found. The action name in the markup doesn't match a controller method. Typo in the method name.
Type coercion issue. Aura's attribute types are strict. Setting an Integer attribute to a String throws. Validate types before set.
Each category has a different fix. Read the bracketed message carefully.
The Apex side: AuraHandledException
If your Aura controller calls an Apex method that throws, the framework wraps the throw as an Aura action error. The Apex side should use AuraHandledException instead of the platform's native exceptions:
@AuraEnabled
public static Decimal calculateRevenue(Id accountId, Decimal growthRate) {
try {
Account a = [SELECT AnnualRevenue FROM Account WHERE Id = :accountId LIMIT 1];
return a.AnnualRevenue * growthRate;
} catch (Exception e) {
throw new AuraHandledException('Could not load account: ' + e.getMessage());
}
}
The AuraHandledException message reaches the client cleanly. Native exceptions (NullPointerException, QueryException) often get truncated or replaced with a generic "An internal server error has occurred" message that's useless for debugging.
Migration from Aura to LWC
Aura is being progressively deprecated in favor of LWC. New components should be LWC. The Action-failed error class disappears with the migration because LWC uses standard JavaScript errors directly, not framework-wrapped ones.
For each Aura component you touch, consider whether the migration to LWC is feasible. The LWC equivalent of Action failed is just a plain JavaScript error, easier to read and debug.
If you can't migrate yet, applying the safe-execute pattern above prevents most of the user-facing breakage.
Debugging with browser DevTools
The Aura error appears as a red banner in the UI, but the full stack trace lives in the browser console. Open DevTools, find the Action failed log line, and expand it. The full error object includes:
- The original JavaScript error message and stack.
- The component instance and parent chain.
- The action name and its arguments.
For complex error chains, the stack trace shows which controller method called which helper method that ultimately threw. The diagnostic depth is much higher than the user-facing banner suggests.
Storage and quota considerations
Aura's client-side caching has quotas. Heavy use of component.set and component.get against large objects can hit storage limits, producing StorageDisabled errors wrapped as action failures.
The fix: don't store large objects in component attributes. Keep attributes scalar or small. For large data sets, fetch on demand instead of caching client-side.
Lifecycle handlers
Aura components have lifecycle handlers (init, afterRender, etc.) that fire automatically. Errors in these throw as action errors named for the handler:
Action failed: c:myComponent$controller$init [Cannot read property...]
The init handler is the most common offender because it runs before user interaction. Components that depend on async data shouldn't access that data in init; defer to the wire response.
Test patterns
Aura testing is more complex than LWC testing. The Lightning Testing Service (Jasmine-based) lets you write tests against components in a sandbox, but the setup overhead is significant. For new code, prefer LWC where Jest testing is straightforward.
For existing Aura components, the Lightning Testing Service still works:
describe('opportunityForecast', function() {
it('handles missing selectedAccount gracefully', function() {
var component = $T.createComponent('c:opportunityForecast');
// ... setup
$T.callAction(component, 'calculateRevenue');
expect(component.get('v.errorMessage')).toContain('select an account');
});
});
A diagnostic checklist
When you see an Action failed error in production:
- Open the browser console and find the full error.
- Read the bracketed JavaScript message carefully.
- Identify whether the error originated client-side (in JS) or server-side (from Apex).
- For client-side, audit the controller method for null reads.
- For server-side, audit the Apex method for exceptions that aren't being wrapped as
AuraHandledException. - Add a try/catch or null guard at the offending line.
- Test the path that produces the error.
The checklist takes ten minutes per incident. Most action-failed errors resolve via steps 4 or 5.
A look at the broader Aura framework
Aura was Salesforce's component framework before LWC. It uses a custom JavaScript runtime with component.get / component.set for attribute access, controller methods for event handling, and a server-side action pattern for Apex callbacks. The framework predates modern JavaScript module systems and has its own conventions.
The convention that produces this error: every controller method is invoked through an action object, and the framework reports errors against that object rather than the underlying function. The wrapping is consistent but verbose.
When LWC launched, the goal was to use standard web platform conventions (ES modules, web components, plain JavaScript errors). For new components, LWC is the obvious choice. For existing Aura code, you can usually keep it running until the next major refactor.
Server-side action failures
When an Aura action calls Apex (via $A.enqueueAction and a server-defined action), the Apex result comes back as an Aura.Action callback. If the Apex throws, the callback's getState() returns 'ERROR' and getError() returns the error details:
var action = component.get('c.fetchAccountData');
action.setCallback(this, function(response) {
var state = response.getState();
if (state === 'SUCCESS') {
component.set('v.data', response.getReturnValue());
} else if (state === 'ERROR') {
var errors = response.getError();
var msg = errors && errors[0] && errors[0].message ? errors[0].message : 'Unknown error';
component.set('v.errorMessage', msg);
}
});
$A.enqueueAction(action);
The callback handles both success and error paths. Without explicit handling, the framework throws the Action failed error.
When the bracket message says "[object Object]"
A common confusion: the bracket contents read [object Object] instead of a useful message. This happens when the error is an object (not a string) and JavaScript's default coercion produces "[object Object]" when concatenating.
The fix is to read the object's properties explicitly. In the controller's catch, log the error directly: console.error('Error:', error) instead of console.log('Error: ' + error). The first form expands the object in the console; the second produces "[object Object]".
Handling errors at the component boundary
A pattern that works well for Aura components: wrap the component's entire controller in a try/catch at the entry point, and surface every uncaught error through a consistent error attribute. The component's markup reads that attribute and renders an inline error banner whenever it's set.
({
handleAnyAction: function(component, event, helper) {
try {
var actionName = event.getSource().get('v.name');
helper[actionName](component, event);
} catch (e) {
component.set('v.errorBanner', e.message || 'Action failed');
console.error('Component error:', e);
}
}
});
The single handler dispatches to helpers by name. The catch covers every action; the error banner is always populated; the console always has the diagnostic. Once you've set this up for a component, individual actions don't need their own try/catch.
The platform's debug log for client-side issues
Apex debug logs are server-side; they don't see client-side errors. For the client side, the browser console is the diagnostic surface. Modern browsers preserve the console log across navigations if you enable "Preserve log" in DevTools.
For users who can't open DevTools (non-technical end users reporting bugs), a "Diagnostic" button in the UI that copies the last 50 lines of console output to the clipboard is sometimes worth building. Users paste the output into a support ticket; the support team gets exact reproduction info.
A subtle source: timing issues in afterRender
Aura's afterRender event fires after the DOM updates. Code in afterRender that depends on attributes set by a different controller method can read undefined values if the rendering hasn't fully completed. The fix is usually to defer the work or to guard the read.
A note on Lightning App Builder errors
When an Aura component fails inside the Lightning App Builder (the design-time editor admins use to compose pages), the error format is similar but the context is different: design-time errors should never happen, because the App Builder evaluates components against safe defaults. If they do, the component's defaults are off.
Audit the component's default attribute values and the App Builder design properties (declared via <design:component> metadata). Defaults that work at runtime might fail when App Builder substitutes its own preview values.
Performance implications
Wrapping every controller call in try/catch has small overhead but the cost is negligible compared to the cost of a user-facing error. Apply the wrapping defensively; the performance overhead doesn't matter for the rare error path.
For very hot controllers (called many times per render), profile before assuming. Aura's framework overhead dominates the per-call cost; your try/catch is in the noise.
Further reading from Salesforce
- Aura Components Developer Guide: Errors
- Apex Developer Guide: AuraHandledException
- Aura Components Developer Guide: Controller Methods
- Salesforce Help: Migrate Aura to LWC
- Trailhead: Lightning Aura Components Basics
Related dictionary terms
Share this fix
Related Lightning · LWC errors
@wire(getRecord, ...) requires the fields property
Lightning · LWCYou used `getRecord` from `lightning/uiRecordApi` without specifying which fields to fetch. LDS doesn't auto-fetch all fields like an old-sc…
Cannot find component: c:myComponent
Lightning · LWCThe Lightning runtime tried to instantiate a component by name and the platform doesn't have it — the bundle didn't deploy, the namespace pr…
Cannot read properties of undefined (reading 'X') — in LWC component lifecycle
Lightning · LWCPlain JavaScript TypeError, but in LWC it almost always means a `@wire` result was read in `connectedCallback` or `renderedCallback` before …
Lightning component cannot be created: c:myComponent
Lightning · LWCThe framework couldn't instantiate a Lightning component at runtime — usually a missing dependency, a permission gap, or a static-resource l…
LWC1009: <template> directives are not allowed at the top level
Lightning · LWCYou put `if:true`, `for:each`, `iterator`, or another LWC template directive on the *root* `<template>` of an LWC HTML file. Directives belo…