You expected a moving average or order to appear on the chart, but Pine highlights a word and says "Undeclared identifier." The message feels almost too basic, especially when you are sure you defined the value somewhere. The Pine Editor on TradingView is deliberately strict, which is useful once you know what it is protecting you from, but not very comforting when you need one line fixed now.
The compiler is being literal: at the line it is reading, the name has not been declared in a usable scope. That can mean a genuine typo, a variable declared after it is used, an old function name missing its namespace, or code copied from another Pine version. The fix is not to keep prompting for a complete new script. It is to identify which of those relationships is broken.
What this error actually means
An identifier is any name Pine uses to find something: your variable name, a built-in namespace such as ta, a function, or a named input. Pine has no safe way to infer what an unknown name should mean. It stops before execution because silently guessing could produce a chart that looks valid but uses the wrong calculation.
Pine evaluates declarations in script order on every bar. A value can reference previously declared values and built-ins, but it cannot reach forward to a later declaration. Scope also matters. A name created inside a local block belongs to that block, not automatically to the rest of the script.
The code pattern that causes it
A common version-related form is calling a technical-analysis function without its namespace. Modern Pine places those functions under ta. If a tutorial, old answer, or general AI output gives you the shorter call, the compiler does not know what sma is supposed to be.
//@version=6
indicator("Namespace example", overlay = true)
fastAverage = sma(close, 20)
plot(fastAverage)The identifier Pine cannot resolve is sma, not close or fastAverage. The line is structurally reasonable, which is why this error often sends people looking at parentheses or indentation first. The issue is that the function belongs to the ta namespace. Similar failures happen with rsi, atr, crossover, highest, and many other functions when older snippets are mixed with v6 code.
The smallest useful fix
//@version=6
indicator("Namespace example", overlay = true)
fastAverage = ta.sma(close, 20)
plot(fastAverage)The smallest fix is the ta prefix. Do not rename fastAverage, rebuild the indicator declaration, or replace every line around it. Start from the exact highlighted identifier, search for the official namespace or your own intended declaration, and make the minimum change that restores that relationship.
If the missing name is your own variable, check spelling and order before assuming a Pine version issue. Pine is case-sensitive, so signal, Signal, and SIGNAL are three different names. Also check whether you defined the value only inside an if block. Declare a variable in an outer scope when later code must use it, then update it inside the condition with := where appropriate.
How to diagnose it without guessing
Read the error as a lookup failure. First, identify the exact word underlined. Second, search the script for its first intended definition. Third, ask whether it is a built-in that needs a namespace, a user value declared too late, or a variable trapped in local scope. This sequence is faster than changing several lines and losing the compiler signal that pointed at the real problem.
Keep related declarations near the top of the script, use descriptive names consistently, and prefer current v6 examples from the official documentation. When you pull code from an older source, verify the version annotation and function namespace before merging it into a working script. Those habits remove most undeclared-identifier errors before the editor sees them.
Three lookalike problems that need different fixes
Declaration order, scope, and reassignment can all surface as a missing-name problem, but they are not interchangeable. A declaration-order issue means the name appears below its first use. A scope issue means the name exists only inside an if, loop, or function. A reassignment issue occurs when a variable was initialized correctly but later needs := rather than =. Read the surrounding declaration before applying a pattern from a different category.
A safe outer-scope pattern is to initialize a value before the condition, then update it only when the condition occurs. For example, declare float lastSignalPrice = na near the other state values, then use lastSignalPrice := close inside the signal block. That gives later plots or labels a stable name to reference without pretending the value exists before the first signal.
A concrete scope pattern to practice
Suppose an indicator needs to remember the closing price of the most recent crossover. The value must exist before a later plot or label can reference it, even though it will be empty until the first crossover. Put the declaration in global scope with float lastCrossPrice = na. Then calculate the crossover condition normally and update lastCrossPrice := close inside the conditional. The declaration gives the script a stable name. The reassignment updates its series value only on bars that meet the condition.
This pattern also explains why declaring lastCrossPrice inside the if block is a problem when you later plot it outside the block. The variable is not merely empty there. It does not exist in that outer scope. Moving only the declaration outward, rather than moving every calculation, keeps the condition local and makes the variable available to the chart output that needs it.
When a missing name appears in a larger file, search for the nearest intended declaration and ask whether it represents temporary local work, persistent state, or a built-in. That classification narrows the correct repair immediately. It also helps you write better requests to any assistant: name the variable, its intended lifetime, and the block that needs to read it. A precise request produces a smaller, easier-to-review correction.
How to read the compiler message with the source around it
The word underlined by Pine is the name it failed to resolve, but the most useful context is usually the two declarations above it and the block that contains it. If the name follows a dot, inspect the object or namespace before the dot. If it appears on the left side of :=, inspect where that variable was first initialized. If it appears in a plot, trace the series value backward rather than changing the plot. This approach turns a terse compiler message into a local source-reading exercise.
A practical example is a crossover flag that is computed in one block and used later for a marker. Define the condition with a clear name such as longCross = ta.crossover(fast, slow) at global scope when several parts of the indicator need it. A plotshape call, an alert condition, and a label can all reference that same name. Defining it once prevents three slightly different expressions from drifting apart and makes it obvious which name would be missing if a later edit removes it.
Avoid using a generic name such as value, result, or signal for several unrelated concepts. Pine permits reassignment, and a vague name can survive compilation while making a later lookup error difficult to diagnose. Prefer names that reveal both what the value represents and, where useful, its timeframe or role, such as dailyClose, fastAverage, or entryCondition. The code becomes easier for you to search and easier for an assistant to modify without confusing two similar variables.
After the compiler accepts the fix, check the first few historical bars as well as the latest bar. A globally declared series can correctly exist while still being na before enough data is available for its calculation. That is a runtime-state question, not an undeclared-identifier problem. Keeping those two questions separate prevents a valid declaration from being replaced with a misleading fallback value just to make an early plot look populated.
Keep a lookup error from becoming a rewrite
For this error, the best correction is usually one name, one namespace, or one declaration. A standard chat session without Pine Editor feedback can help explain the category, but you still need to transport the compiler message and review its response. If it returns a whole script, you have to verify every unchanged condition again even though only one identifier was wrong.
PineScripter is useful here because its in-app lint workflow can send a specific finding through an AI correction loop and apply a focused edit rather than defaulting to a fresh full-file answer. Its retrieved Pine Script v5 and v6 manual context helps the model work from current signatures. Review the diff, then validate the final result in the Pine Editor.
For the underlying language rule, consult TradingView documentation on script structure. Related reading: function-reference fixes, the Pine Script type system, the broader compile-error guide.
A practical checklist before you paste again
Confirm the highlighted word is spelled exactly the same everywhere. Check that it is declared before use, is available in the current scope, and has the correct built-in namespace. Then compile again before changing anything else. One clean compile result gives you a trustworthy next signal.
An undeclared identifier is usually a small correction, not evidence that the whole script is wrong. Treat it as a precise lookup problem, fix the named relationship, and keep the rest of your working logic intact.
Disclaimer: PineScripter is a coding tool for Pine Script development. It does not provide financial advice and does not guarantee trading profits. Always backtest strategies thoroughly and understand the risks before live trading.