Skip to content
Oracle Database

Oracle Error ORA-01008

value for bind variable placeholder was not provided

Applies to: Oracle Database 19c, 21c, 23ai and 26ai (wording differs: see below)
Last technically reviewed 24 October 2026 on Oracle Database Error Messages reference (26ai, 21c and 19c); not run locally
The full message
ORA-01008: value for bind variable placeholder :STATUS was not provided
Other forms of this message
Oracle Database 19c and 21c wording (no placeholder named)
ORA-01008: not all variables bound
From dynamic SQL in a PL/SQL block
ORA-01008: value for bind variable placeholder :STATUS was not provided
ORA-06512: at "SHOP.COUNT_ORDERS", line 9
Error code
ORA-01008
Product
Oracle Database
Versions
Oracle Database 19c, 21c, 23ai and 26ai (wording differs: see below)
Last reviewed
24 October 2026

What it means

ORA-01008 means a SQL or PL/SQL statement with bind variable placeholders (such as :status or :1) was executed without a value for one of them.

A placeholder in a statement, written with a colon, is a slot that the caller fills when the statement runs. Oracle checks that every slot has a value before executing; if one is missing it raises ORA-01008. Current releases name the placeholder that has no value (or its position); 19c and 21c print only "not all variables bound". The placeholder shown on this page is illustrative.

How slots are matched to values depends on the binding style, and that is where most cases come from. Oracle's reference says: with named binding, one value per name is enough even if the name is repeated; with positional binding, every position needs a value, even if the same name appears twice. In PL/SQL dynamic SQL (EXECUTE IMMEDIATE, OPEN FOR), a SQL statement binds by position, while a dynamic anonymous block or CALL binds each unique name once.

Common causes

  • The USING clause of EXECUTE IMMEDIATE or OPEN FOR has fewer values than the dynamic statement has placeholders.
  • A placeholder name is repeated in a dynamic SQL statement (for example :st IS NULL OR status = :st), which binds by position, but only one value is supplied.
  • Dynamic SQL is assembled from optional filters, and a filter added to the text did not add its value to the bind list.
  • Application code binds by position with a driver while the SQL repeats a named placeholder, or a value is skipped when an optional parameter is empty.
  • The statement text and the bind list come from different versions of the code, for example after a placeholder was added to the SQL only.

Diagnose it

Read-only These queries only read the data dictionary (USER_, ALL_ and DBA_ views) and dynamic performance views (V$). They do not change data, privileges or settings, so they are safe to run first. DBA_ and V$ views need the matching privileges.

Count placeholders against values

Log the exact statement text and the values bound, at the point of execution. Count every colon placeholder (each occurrence, if the statement is SQL bound by position) and compare with the number of values. Colons inside quoted string literals are not placeholders.

Find the dynamic SQL in stored code

SELECT name, type, line, text
FROM all_source
WHERE owner = 'SHOP'
  AND (UPPER(text) LIKE '%EXECUTE IMMEDIATE%' OR UPPER(text) LIKE '%OPEN %FOR%')
ORDER BY name, line;
What to look for

Every place that runs dynamic SQL. Start with the unit and line from the ORA-06512 line under the error, and check its USING clause.

See the statement text the database parsed

V$SQL needs privileges such as SELECT_CATALOG_ROLE; ask a DBA if you cannot query it.

SELECT sql_id, parsing_schema_name, sql_text
FROM v$sql
WHERE parsing_schema_name = 'SHOP'
  AND sql_text LIKE '%FROM orders%:%'
ORDER BY last_active_time DESC
FETCH FIRST 10 ROWS ONLY;
What to look for

The statement as the application sent it, with its placeholders, which you can compare with the values the code binds.

How to fix it

Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.

Supply one value for each placeholder in the USING clause

Changes schema

For a dynamic SQL statement, list a bind value for every placeholder occurrence, in order. To use the same value twice, repeat the variable.

CREATE OR REPLACE FUNCTION shop.count_orders (p_status IN VARCHAR2)
  RETURN NUMBER
IS
  v_count NUMBER;
BEGIN
  EXECUTE IMMEDIATE
    'SELECT COUNT(*) FROM shop.orders WHERE (:st IS NULL OR status = :st)'
    INTO v_count
    USING p_status, p_status;   -- two occurrences, two values
  RETURN v_count;
END;
/

Build optional filters and their binds together

Changes schema

When filters are optional, keep the statement fixed and let NULL switch a filter off, as above, so the number of placeholders never changes. For a truly variable number of placeholders, DBMS_SQL lets you bind each one by name as you add it.

CREATE OR REPLACE FUNCTION shop.count_customer_orders (
  p_customer_id IN NUMBER,
  p_status      IN VARCHAR2 DEFAULT NULL)
  RETURN NUMBER
IS
  v_sql   VARCHAR2(400) := 'SELECT COUNT(*) FROM shop.orders WHERE customer_id = :cust';
  v_count NUMBER;
  c       INTEGER := DBMS_SQL.OPEN_CURSOR;
  ignore  INTEGER;
BEGIN
  IF p_status IS NOT NULL THEN
    v_sql := v_sql || ' AND status = :status';
  END IF;
  DBMS_SQL.PARSE(c, v_sql, DBMS_SQL.NATIVE);
  DBMS_SQL.BIND_VARIABLE(c, ':cust', p_customer_id);
  IF p_status IS NOT NULL THEN
    DBMS_SQL.BIND_VARIABLE(c, ':status', p_status);   -- bound with the text that needs it
  END IF;
  DBMS_SQL.DEFINE_COLUMN(c, 1, v_count);
  ignore := DBMS_SQL.EXECUTE_AND_FETCH(c);
  DBMS_SQL.COLUMN_VALUE(c, 1, v_count);
  DBMS_SQL.CLOSE_CURSOR(c);
  RETURN v_count;
END;
/

In application code, bind every placeholder, by name where possible

Client or network side

Oracle's drivers support named or positional binding. Binding by name (a dictionary or named parameters) needs one value per name, which avoids the repeated-name trap. With positional binding, pass a value for every placeholder position, including NULL for an empty optional parameter, never by skipping it.

Examples

EXECUTE IMMEDIATE with a value missing from USING

Not reproduced here: no Oracle Database is installed for this site. The message format is the current wording in Oracle's error reference, which says it names the placeholder or its position; how the name is printed is illustrative. Oracle Database 19c prints "ORA-01008: not all variables bound".

DECLARE
  v_count NUMBER;
BEGIN
  EXECUTE IMMEDIATE
    'SELECT COUNT(*) FROM orders WHERE customer_id = :cust AND status = :status'
    INTO v_count
    USING 4711;   -- no value for :status
END;
/
Expected result (documented format, not run)
ORA-01008: value for bind variable placeholder :STATUS was not provided
ORA-06512: at line 4

A repeated placeholder in dynamic SQL, bound once

Not reproduced here: no Oracle Database is installed for this site. Oracle's PL/SQL reference documents that a dynamic SQL statement (not a block or CALL) associates placeholders with bind values by position, so a repeated name needs its value repeated. The message layout is from the error reference; the details are illustrative.

DECLARE
  v_count  NUMBER;
  v_status VARCHAR2(20) := 'OPEN';
BEGIN
  EXECUTE IMMEDIATE
    'SELECT COUNT(*) FROM orders WHERE (:st IS NULL OR status = :st)'
    INTO v_count
    USING v_status;   -- SQL binds by position: two placeholders, one value
END;
/
Expected result (documented format, not run)
ORA-01008: value for bind variable placeholder :ST was not provided
ORA-06512: at line 5

How to prevent it

Keep dynamic SQL statements fixed where you can, with NULL-tolerant filters, so the placeholder count never changes. When text must vary, add each placeholder and its bind in the same step. Prefer binding by name in application drivers.

Never fix ORA-01008 by pasting the value into the SQL text: placeholders are what protect dynamic SQL from SQL injection.

Common questions

How do I fix ORA-01008 not all variables bound?

Count the placeholders in the statement and the values your code supplies. Add the missing value, repeat a value for a repeated placeholder in dynamic SQL, or switch to named binding so each name needs only one value.

Why do I need to pass the same value twice?

A dynamic SQL statement in PL/SQL, and positional binding in drivers, match placeholders to values by position, not by name. Two occurrences of :st are two positions, so they need two values (which can be the same variable).

Why does 19c not say which variable is missing?

The wording changed. Oracle's 19c and 21c references give "not all variables bound"; the current reference names the placeholder without a value, or its position. The cause and fix are the same.

Learn more on CodeWithSQL

Official documentation

Last technically reviewed 24 October 2026; examples and diagnostics run on Oracle Database Error Messages reference (26ai, 21c and 19c); not run locally. Messages and explanations follow Oracle's Database Error Messages reference; no Oracle Database was available, so the examples were not run locally.

Still stuck on an Oracle error?

Browse the full Oracle error library, or get hands-on help from an experienced SQL professional.