Quick answer: The most common cause is not adding the Input Mapping Context to the local player's Enhanced Input subsystem. Creating Input Action and Mapping Context assets is not enough; you must call AddMappingContext on the EnhancedInputLocalPlayerSubsystem during BeginPlay to register the context.

Here is how to fix Unreal enhanced input action not triggering. You created Input Action assets, set up an Input Mapping Context, bound everything in your character class, and pressed the key — nothing happens. No movement, no jump, no action. The Enhanced Input system in Unreal Engine 5 replaces the legacy input system with a more flexible architecture, but that flexibility comes with more setup steps and more places where things can silently fail.

The Symptom

You press a key that is mapped to an Input Action in your Input Mapping Context. The bound function on your character or controller never executes. There are no errors in the Output Log. The action simply does not fire.

In some cases, some actions work but others do not. You might have movement working but jump not triggering, or the action fires once but does not repeat for held inputs. Or the input works in PIE (Play In Editor) but not in a packaged build.

Adding the Mapping Context

This is the number one cause of Enhanced Input not working. You must explicitly add your Input Mapping Context to the local player’s Enhanced Input subsystem at runtime. Creating the IMC asset and configuring it in the editor is not enough.

// Add the mapping context in the character's BeginPlay
void AMyCharacter::BeginPlay()
{
    Super::BeginPlay();

    if (APlayerController* PC = Cast<APlayerController>(GetController()))
    {
        if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
            ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(
                PC->GetLocalPlayer()))
        {
            Subsystem->AddMappingContext(DefaultMappingContext, 0);
            UE_LOG(LogTemp, Log, TEXT("Mapping context added"));
        }
        else
        {
            UE_LOG(LogTemp, Error, TEXT("Enhanced Input subsystem not found"));
        }
    }
}

The second parameter is the priority. If you have multiple mapping contexts (one for on-foot, one for driving, one for menus), the context with the higher priority value takes precedence when the same key is mapped in multiple contexts.

If you add the mapping context from the Player Controller instead of the Character, make sure the controller has a valid local player at the time of the call. In multiplayer, only the locally controlled player has a valid local player subsystem.

In Blueprints, use the Get Enhanced Input Local Player Subsystem node, then call Add Mapping Context on it.

Binding Actions in SetupPlayerInputComponent

After the mapping context is registered, you need to bind each Input Action to a function. This happens in SetupPlayerInputComponent, which Unreal calls automatically when the character is possessed.

// Bind enhanced input actions
void AMyCharacter::SetupPlayerInputComponent(
    UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // Cast to Enhanced Input Component
    UEnhancedInputComponent* EnhancedInput =
        CastChecked<UEnhancedInputComponent>(PlayerInputComponent);

    // Movement: bind to Triggered for continuous input
    EnhancedInput->BindAction(
        MoveAction, ETriggerEvent::Triggered,
        this, &AMyCharacter::Move);

    // Look: bind to Triggered for continuous mouse delta
    EnhancedInput->BindAction(
        LookAction, ETriggerEvent::Triggered,
        this, &AMyCharacter::Look);

    // Jump: bind to Started for initial press
    EnhancedInput->BindAction(
        JumpAction, ETriggerEvent::Started,
        this, &ACharacter::Jump);

    // Jump release: bind to Completed
    EnhancedInput->BindAction(
        JumpAction, ETriggerEvent::Completed,
        this, &ACharacter::StopJumping);
}

A common mistake is forgetting to cast the InputComponent to UEnhancedInputComponent. If you call BindAction on the base UInputComponent, you are using the legacy input binding which does not understand Enhanced Input actions.

Another mistake: using CastChecked when the project still has the legacy input system as the default. If the default player input class is not UEnhancedInputComponent, the cast asserts and crashes. Check Project Settings → Input → Default Classes → Default Player Input Class should be EnhancedPlayerInput, and Default Input Component Class should be EnhancedInputComponent.

Trigger Types Explained

The Enhanced Input system uses trigger types to define when an action fires. This is where many developers get confused, especially when coming from the legacy input system.

If you bind to ETriggerEvent::Triggered but the action has a Pressed trigger type, the function fires once on press and once on release. If you expected continuous firing during hold, remove the Pressed trigger and leave the triggers array empty, which defaults to a Down trigger.

Here are the trigger events and when they fire:

Started: Fires once when the action first enters the Triggered state. Equivalent to “key pressed” in most cases.

Triggered: Fires every frame while the action remains in the Triggered state. For a held key with no triggers configured, this fires every frame the key is held.

Completed: Fires once when the action leaves the Triggered state. Equivalent to “key released” for simple press/release inputs.

Canceled: Fires if the action is interrupted before completing, such as when the mapping context is removed while the key is held.

The trigger types on the Input Action asset control how the action transitions between states:

// Input Action configuration examples

// Simple button press (jump, interact):
//   Value Type: bool (Digital)
//   Triggers: none (or Down)
//   Bind to: Started for press, Completed for release

// Held action (charge attack):
//   Value Type: bool (Digital)
//   Triggers: Hold (Hold Time Threshold = 0.5)
//   Bind to: Triggered fires after 0.5s hold

// Axis movement (WASD):
//   Value Type: Axis2D (Vector2D)
//   Triggers: none
//   Bind to: Triggered for continuous movement each frame

// Tap action (dodge):
//   Value Type: bool (Digital)
//   Triggers: Tap (Tap Release Time Threshold = 0.2)
//   Bind to: Triggered fires only if key released within 0.2s

Input Modifiers

Modifiers transform the input value before it reaches your bound function. They are configured on the key mapping inside the Input Mapping Context. Common modifiers include Negate (invert the axis), Swizzle (remap XYZ axes), Dead Zone, and Scalar (multiply the value).

A frequent mistake with movement input: you map WASD to an Axis2D action but forget to add modifiers. W and S map to the Y axis, A and D map to the X axis. Without a Negate modifier on S and A, both W/S produce positive Y and both A/D produce positive X, so the character moves in the same direction regardless of key.

// Typical WASD mapping in the Input Mapping Context:
// W -> MoveAction: no modifiers (forward = +Y)
// S -> MoveAction: Negate modifier (backward = -Y)
// A -> MoveAction: Negate + Swizzle YXZ (left = -X)
// D -> MoveAction: Swizzle YXZ (right = +X)

// The Move function receives the combined Axis2D value
void AMyCharacter::Move(const FInputActionValue& Value)
{
    FVector2D MoveInput = Value.Get<FVector2D>();

    // MoveInput.X = right/left, MoveInput.Y = forward/back
    FVector Forward = GetActorForwardVector() * MoveInput.Y;
    FVector Right = GetActorRightVector() * MoveInput.X;

    AddMovementInput(Forward + Right, 1.0f);
}

Legacy Input System Conflicts

If your project was created before UE5 or if you are migrating from the legacy input system, both systems can be active simultaneously. This causes unpredictable behavior where some inputs go to the legacy system and others go to Enhanced Input.

To fully switch to Enhanced Input, go to Project Settings → Input and change:

Default Player Input Class to EnhancedPlayerInput

Default Input Component Class to EnhancedInputComponent

Then remove any legacy BindAxis or BindAction calls from your character code. Having both legacy and enhanced bindings on the same character causes neither to work reliably.

// Remove legacy bindings like these:
// PlayerInputComponent->BindAxis("MoveForward", this, &AMyChar::MoveForward);
// PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AMyChar::Jump);

// Replace with Enhanced Input bindings:
UEnhancedInputComponent* EIC =
    CastChecked<UEnhancedInputComponent>(PlayerInputComponent);
EIC->BindAction(MoveAction, ETriggerEvent::Triggered,
    this, &AMyCharacter::Move);
EIC->BindAction(JumpAction, ETriggerEvent::Started,
    this, &ACharacter::Jump);

Related Issues

If Enhanced Input works but your character does not actually move, the problem may be in the Character Movement Component rather than the input system — see Character Movement not working. If input reaches the character but animations do not respond, check Animation Blueprint not updating for variable sync issues.

If some actions work and others do not, the mapping context is probably registered correctly. Check the trigger type on the broken action — a Pressed trigger on a movement axis silently swallows the input.