MT5 Error 4014: Causes and Fixes in MQL5
By FXNook Lab team
MT5 error 4014 means an MQL5 program called a function that is not permitted in its current context. The fix is to identify the exact function and where it runs, then move the operation to a permitted program type or replace it with a supported approach. It is a runtime restriction, not a compile error and not, by itself, a broker rejection.
The same function can behave differently depending on whether it is called by an Expert Advisor, script, custom indicator, or Strategy Tester run. Start with the program type and execution mode; do not assume the number alone tells you which line or function is responsible.
What MT5 error 4014 means
In MQL5, 4014 is ERR_FUNCTION_NOT_ALLOWED: a function is not allowed to be called in the current situation. The program may compile successfully because the function name and its parameters are valid, then encounter the restriction only when execution reaches that call.
That is different from a compiler message such as an undeclared identifier, which prevents a successful build. It is also different from a trade-server rejection. For example, a CTrade method can return a server retcode describing a refused request; 4014 instead points to an MQL5 function-context restriction. For trade failures, inspect CTrade.ResultRetcode() or the MqlTradeResult, rather than treating every failure as error 4014.
One common case is a custom indicator trying to perform an operation reserved for an EA or script. Another is calling a function that is unavailable in the Strategy Tester. The restriction depends on the particular function, so its MQL5 documentation is the final reference for its allowed contexts.
Find the exact function behind error 4014
The number is a starting point, not a diagnosis. Use the Experts and Journal tabs in MT5 to find the error message and its timestamp, then match that time to the program, chart or tester run, and event being processed. Logs may identify the program and report the runtime failure without giving a useful call stack, so add tracing around the suspected calls if the exact line is not shown.
- Record the context. Note whether the code is an EA, indicator, or script, and whether it ran on a chart or in the Strategy Tester. Also record the event handler involved, such as
OnTick,OnCalculate, orOnStart. - Locate the event in the logs. Open the relevant Experts or Journal tab and compare the error time with your program's own messages. In the Strategy Tester, use the tester's log for that run as well as the terminal logs.
- Narrow the call site. Add a short
Printmessage immediately before and after a suspected function. If the first message appears but the second does not, the failure is likely at that call or during its execution. Reduce a group of calls to one at a time rather than changing several functions together. - Check the documented restriction. Search the MQL5 Reference entry for the function and note limitations for indicators, scripts, EAs, or the tester. The error code alone does not identify the function.
When a call returns an error rather than terminating the program, clear the previous error before the call and read it immediately after the failure. For example, ResetLastError() followed by a failed WebRequest() and then GetLastError() can help distinguish the current failure from an earlier one. Do not use a later unrelated call to infer the cause: another operation may have changed the last-error value.
MetaEditor’s debugger can help when the log is too broad. Set a breakpoint before the suspect call, run the same event or tester setup, and step through the code. This is especially useful when a helper function hides the restricted call several layers below OnCalculate or OnTick.
Common causes and the right fix
| Context and symptom | Likely restriction | Practical fix |
|---|---|---|
| A custom indicator reaches an account-changing operation, such as sending a trade request. | Trade operations are not available from a custom indicator in the same way they are from an EA or script. | Keep the indicator focused on calculations and signals. Have an EA read those signals and carry out the trading logic. |
WebRequest() is called from a custom indicator. | WebRequest() is restricted to EAs and scripts because it is synchronous; it cannot be called from an indicator. | Move the request into an EA or script. If the indicator needs the result, pass data through an appropriate program design rather than making the request inside the indicator. |
WebRequest() runs during a Strategy Tester pass. | WebRequest() is not available in the Strategy Tester. A tester run is not equivalent to a live terminal for external requests. | Use deterministic test data or a local test path that represents the response. Keep the live request path separate and report clearly when the test path is used. |
| A function works in one program but fails in another. | The function has a program-type or runtime-context limitation. | Read that function's MQL5 Reference entry and move it to a permitted context, or choose a documented alternative. |
| The failure occurs only in the tester or only on a chart. | The tester and terminal may provide different permissions or services; an event-specific call may also be reached only in one mode. | Reproduce in the same mode, log the branch taken, and handle the unsupported operation deliberately instead of suppressing the error. |
For WebRequest(), the official documentation describes its program and Strategy Tester restrictions. In a live terminal, the requested server also needs to be present in the allowed URL list under Tools > Options > Expert Advisors. That setting does not make WebRequest available in an indicator or enable it in the tester. See the MQL5 WebRequest documentation for the function's requirements and return behavior.
Do not choose a fix just because it removes the message. The function may be restricted for a reason tied to how the program runs. Preserve the intended behavior: if an EA needs external data, test with a defined substitute and make sure that the substitute cannot be mistaken for a successful live request.
Move an indicator signal into an EA
An indicator should calculate and publish information, not try to place trades. The following small example uses a custom indicator to publish a buffer value of 1 when a completed candle closes above its open, and 0 otherwise. The EA reads the previous bar's value and sends a buy request on a new bar when the signal is 1 and there is no open position for the symbol.
This is a program-structure example, not a trading strategy recommendation. Save the indicator as SignalBuffer.mq5 under MQL5/Indicators, compile it, then save and compile the EA under MQL5/Experts. The EA's iCustom() name must match the indicator file name.
MQL5 custom indicator: SignalBuffer.mq5
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1
#property indicator_type1 DRAW_NONE
#property indicator_label1 "Signal"
double SignalBuffer[];
int OnInit()
{
SetIndexBuffer(0, SignalBuffer, INDICATOR_DATA);
ArraySetAsSeries(SignalBuffer, true);
return INIT_SUCCEEDED;
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
ArraySetAsSeries(open, true);
ArraySetAsSeries(close, true);
int start = (prev_calculated == 0) ? rates_total - 1 : rates_total - prev_calculated;
for(int i = start; i >= 0; --i)
SignalBuffer[i] = (close[i] > open[i]) ? 1.0 : 0.0;
return rates_total;
}
MQL5 Expert Advisor: SignalReader.mq5
#include <Trade/Trade.mqh>
input double Lots = 0.10;
CTrade trade;
int signalHandle = INVALID_HANDLE;
datetime lastBarTime = 0;
int OnInit()
{
signalHandle = iCustom(_Symbol, _Period, "SignalBuffer");
if(signalHandle == INVALID_HANDLE)
{
Print("Could not create SignalBuffer indicator handle. Error: ", GetLastError());
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(signalHandle != INVALID_HANDLE)
IndicatorRelease(signalHandle);
}
void OnTick()
{
datetime barTime = iTime(_Symbol, _Period, 0);
if(barTime == 0 || barTime == lastBarTime)
return;
lastBarTime = barTime;
double signal[1];
if(CopyBuffer(signalHandle, 0, 1, 1, signal) != 1)
{
Print("Could not read the previous-bar signal. Error: ", GetLastError());
return;
}
if(signal[0] > 0.5 && !PositionSelect(_Symbol))
{
if(!trade.Buy(Lots, _Symbol))
Print("Buy request failed. Retcode: ", trade.ResultRetcode(),
" ", trade.ResultRetcodeDescription());
}
}
The indicator does not call a trading function. It only writes to a buffer; the EA creates the indicator handle, reads the completed bar using CopyBuffer(), and uses CTrade from its own event handler. This division avoids placing an EA-only operation in an indicator context, which is a common route to 4014.
The example keeps its scope small. It uses one symbol and a simple position check; adapt order sizing, position handling, signal rules, and failure handling to the actual program requirements. A successful compile confirms the syntax, but it does not prove that the intended signal is read or that a broker will accept a request.
If error 4014 appears only in Strategy Tester
A tester run has restrictions that do not match every live-terminal capability. The clearest example is WebRequest(), which cannot be executed in the Strategy Tester. An external service may be reachable by a live EA after the terminal's URL permissions are configured, while the same request is unavailable during a test.
First, verify that the tester is actually reaching the request. Add a log message immediately before it and log the selected test mode or branch. If the request is reached, the tester restriction is a likely explanation; if it is not, trace the condition that should have led to the call instead. This keeps a coincidentally nearby 4014 from sending you after the wrong function.
For repeatable tests, supply a local or otherwise deterministic input that represents the external response, and make the test path explicit in the code or inputs. The live path can call WebRequest() from an EA, while the tester path reads its test data or reports that the external call is unavailable. Do not catch the failure and silently return a normal-looking value: that can make the test appear to pass while skipping logic the live EA depends on.
If you need broader help with tester setup, see MT5 Strategy Tester Not Working: Causes and Fixes. The goal is not to make the tester imitate an external service invisibly; it is to make clear which input path was used and what behavior was actually tested. Tested results do not guarantee future results.
Debugging checklist before changing the code
- Record program type and execution mode. Write down whether the code is an EA, indicator, or script, and whether the failure is on a chart, during initialization, or in the Strategy Tester.
- Identify the exact call. Use the timestamp, program messages, debugger, and narrow tracing to find the function reached immediately before 4014.
- Read the function's documented restrictions. Confirm whether it is permitted from that program type and runtime context. Do not generalize from another function that happens to be in the same library.
- Reproduce with the smallest test. Isolate the call in a short program or reduce the original branch to the fewest necessary operations. Keep the failing execution mode unchanged.
- Choose a fix that preserves behavior. Move the operation to an EA or script when required, or provide a clear tester substitute for an unsupported external dependency. Preserve the signal or data flow the original code needs.
- Retest the relevant path. Verify both the context that originally failed and any separate context that uses the alternative path. Inspect the logs for skipped work as well as for the absence of 4014.
Confirm the fix in MetaEditor and MT5
Compile the modified program in MetaEditor and make sure the correct MQL5 file and program type are selected. Then run the relevant EA, indicator, or script in the same chart or tester context that produced the error. A compile pass does not exercise runtime restrictions, so the test must reach the previously failing call path.
Read the Experts and Journal logs after the run. Confirm that 4014 no longer appears and that the expected operation actually happened: the EA read the signal, the supported request path ran, or the tester used the stated substitute. If a trade request is involved, inspect its trade retcode separately; absence of 4014 does not mean the broker accepted the request.
If you cannot pin the failure to a call or the program needs a structural change, FXNook Lab's MQL4/MQL5 error fixing page accepts code with or without MetaEditor errors, finds the cause, compiles again, and shows what changed. Your practical next step is to isolate the function that triggers 4014, check its documented context limits, and test the smallest appropriate fix in the same execution mode.
Questions
What does error 4014 mean in MQL5?
Error 4014 is ERR_FUNCTION_NOT_ALLOWED: the program called a function that is not permitted in its current context. Find the function and the program type or runtime mode where it runs, then consult that function's MQL5 documentation for the supported contexts.
Why does WebRequest cause error 4014 in the MT5 Strategy Tester?
WebRequest is unavailable in the Strategy Tester, so a tester run cannot use it to contact an external service. Use a clearly identified, deterministic test input instead, and keep the live request path separate rather than silently treating a failed request as valid data.
Can an MT5 indicator call trading functions?
A custom indicator should not execute trade operations; trading logic belongs in an EA or script. Have the indicator publish its signal through a buffer, then let an EA read that buffer and decide whether to submit a trade request.