Google BigQuery

BigQuery CAST and SAFE_CAST: convert data types without errors

CAST converts a value to another data type and stops the query when a value cannot be converted. SAFE_CAST does the same and returns NULL instead. This guide shows both on strings, numbers and dates with results from real runs, and explains the SAFE. prefix and where it does not work.

Google BigQueryAlyona Samovar6 min read

BigQuery CAST and SAFE_CAST: convert data types without errors

CAST(expression AS type) converts a value to another data type, and stops the whole query if a single value cannot be converted. SAFE_CAST(expression AS type) does the same conversion and returns NULL for the values that fail.

SELECT
  CAST('42' AS INT64),       -- 42
  SAFE_CAST('abc' AS INT64); -- NULL

CAST('abc' AS INT64) would end the query with “Bad int64 value: abc”. Every result on this page comes from a run in BigQuery on 6 October 2026.

Note: Originally published in April 2024. Fully updated in October 2026 with re-run examples and a section on the SAFE. prefix.

When to use CAST and when SAFE_CAST

When to use CAST and when SAFE_CAST

  • Use CAST when a failed conversion means the data is broken and you want to know: a pipeline step, a test, a column you control.
  • Use SAFE_CAST when the column comes from outside and some values will be dirty: a spreadsheet import, a form field, an event parameter.

SAFE_CAST has a cost that is easy to miss. It turns bad values into NULL and tells nobody. A sum over the result is simply smaller. So when you use it, count what it dropped:

SELECT
  COUNT(*) AS total_rows,
  COUNTIF(raw_value IS NOT NULL
    AND SAFE_CAST(raw_value AS INT64) IS NULL)
    AS failed_to_convert
FROM UNNEST(['42', 'abc', '1,200', NULL])
  AS raw_value;
-- 4, 2

Two of four rows failed. That number belongs next to any report built on a SAFE_CAST.

Strings to numbers

Strings to numbers

SELECT
  CAST('42' AS INT64),               -- 42
  CAST('3.7' AS FLOAT64),            -- 3.7
  CAST('19.99' AS NUMERIC),          -- 19.99
  SAFE_CAST(' 42 ' AS INT64),        -- 42
  SAFE_CAST('1,200' AS INT64),       -- NULL
  SAFE_CAST('3.7' AS INT64),         -- NULL
  SAFE_CAST('' AS INT64),            -- NULL
  SAFE_CAST('12abc' AS INT64),       -- NULL
  SAFE_CAST('0x1F' AS INT64);        -- 31

What those results say:

  • Surrounding spaces are ignored. ' 42 ' converts.
  • A thousands separator is not. '1,200' fails. Remove it first: SAFE_CAST(REPLACE(x, ',', '') AS INT64) returns 1200.
  • A decimal string does not cast to an integer. '3.7' to INT64 is NULL. Cast to FLOAT64 or NUMERIC first.
  • An empty string is not zero. It is NULL after SAFE_CAST and an error after CAST.
  • A hex string with the 0x prefix does convert.

For money, cast to NUMERIC, not FLOAT64. Floating point cannot hold every decimal exactly, and it cannot hold every large integer either: CAST(9007199254740993 AS FLOAT64) returns 9007199254740992.

The Turning Point

OWOX Data Marts

See your first report built in real time. 15 minutes.

  1. Connect your data warehouse
  2. Pick your metrics
  3. Get a live Google Sheets report

In the time it takes to write a ticket. Then imagine never writing that ticket again.

Book a Demo

We'll use your actual use case

Numbers to integers: CAST rounds

Numbers to integers: CAST rounds

SELECT
  CAST(3.7 AS INT64),   -- 4
  CAST(2.5 AS INT64),   -- 3
  CAST(-3.5 AS INT64);  -- -4

BigQuery rounds when it casts a float to an integer, and halfway cases go away from zero. It does not truncate, which is what many other languages do. If you want the decimal part dropped, use TRUNC(x) before the cast. More in mathematical functions.

Anything to a string

Anything to a string

SELECT
  CAST(42 AS STRING),                  -- '42'
  CAST(DATE '2026-10-06' AS STRING),   -- '2026-10-06'
  CAST(TRUE AS STRING),                -- 'true'
  CAST(b'hello' AS STRING);            -- 'hello'

Casting to STRING almost never fails. The exception is BYTES that are not valid UTF-8: CAST(b'\xff' AS STRING) is an error and SAFE_CAST of the same value is NULL.

To control the layout, add a FORMAT clause:

SELECT CAST(DATE '2026-10-06'
  AS STRING FORMAT 'DD/MM/YYYY');
-- '06/10/2026'

Strings to dates

Strings to dates

SELECT
  CAST('2026-10-06' AS DATE),          -- 2026-10-06
  SAFE_CAST('2026-02-30' AS DATE),     -- NULL
  CAST('06/10/2026'
    AS DATE FORMAT 'DD/MM/YYYY');      -- 2026-10-06

Without a FORMAT clause, a string must be in YYYY-MM-DD form to cast to a DATE. For any other layout either add FORMAT, or use PARSE_DATE with a format string. Both are covered with their week and time zone traps in BigQuery date functions.

A timestamp casts to a date in UTC. CAST(TIMESTAMP '2026-10-06 23:30:00+00' AS DATE) is 2026-10-06, although it is already 7 October in Tokyo. When the day matters, use DATE(ts, 'Asia/Tokyo'), which lets you name the time zone.

Booleans

Booleans

SELECT
  CAST('true' AS BOOL),      -- true
  CAST(1 AS BOOL),           -- true
  SAFE_CAST('yes' AS BOOL);  -- NULL

Only the strings true and false convert, in any letter case. 'yes', 'Y' and '1' do not: map them with a CASE expression.

The SAFE. prefix is not SAFE_CAST

The SAFE. prefix is not SAFE_CAST

SAFE_CAST is one function. SAFE. is a prefix you can put in front of many other functions to get NULL where they would raise an error.

SELECT
  SAFE.PARSE_DATE('%d/%m/%Y', '31/02/2026'),
  -- NULL
  SAFE.FROM_BASE64('not base64!'),
  -- NULL
  SAFE.SUBSTR('abc', 0, -2);
  -- NULL

Google documents the prefix under function calls. A few functions have a dedicated safe version instead, such as SAFE_DIVIDE(10, 0), which returns NULL where 10 / 0 is an error, and SAFE_CONVERT_BYTES_TO_STRING.

“SAFE with function date is not supported”

The prefix does not work everywhere. SAFE.DATE(string_column) returns this error instead of a date. The fix is one of the two functions that are built for it:

SELECT
  SAFE_CAST(s AS DATE),
  SAFE.PARSE_DATE('%Y-%m-%d', s)
FROM UNNEST(['2026-02-30']) AS s;
-- NULL, NULL

SAFE_CAST for the YYYY-MM-DD form, SAFE.PARSE_DATE for anything else.

What can be cast to what

What can be cast to what

The pairs people need most. The full matrix is in Google’s conversion rules.

From To Works when
STRING INT64 whole number, optional sign, optional 0x
STRING FLOAT64, NUMERIC a valid decimal number
STRING DATE YYYY-MM-DD, or a FORMAT clause
STRING BOOL true or false
FLOAT64 INT64 always; rounds half away from zero
INT64 BOOL always; 0 is false, anything else true
TIMESTAMP DATE always; in UTC
BYTES STRING valid UTF-8
anything STRING nearly always

For the rest of the conversion functions, such as PARSE_NUMERIC and TO_JSON_STRING, see conversion functions in BigQuery.

Errors and what they mean

Errors and what they mean

“Bad int64 value”. A string that is not a whole number went into CAST(... AS INT64). Find the offenders with WHERE SAFE_CAST(x AS INT64) IS NULL AND x IS NOT NULL.

“Invalid date”. The string is not in YYYY-MM-DD form, or the date does not exist, such as 30 February.

“Invalid cast from X to Y”. That pair is not allowed at all, for example DATE to INT64. SAFE_CAST does not help here: it protects against bad values, not against an impossible conversion. Use the function made for it, in this case UNIX_DATE.

“SAFE with function date is not supported”. See above.

One cast, many reports

One cast, many reports

Type conversion is where a clean-looking number is usually decided. Whether '1,200' became 1200 or NULL, whether a price went through FLOAT64, whether an evening order was dated in UTC: each choice is one function call, made once, by whoever wrote the query.

Then the query gets copied, and the second copy makes the choice differently. That is why the casts belong in one place. In OWOX Data Marts the query that does the cleaning is a Data Mart: your SQL, with its description and owner, run in your warehouse, and every report reads the already-typed columns from it. OWOX does not clean or convert anything for you. It makes sure the conversion you wrote is the only one in use.

Data Setup tab of the Unified Ad Spend Data Mart in OWOX Data Marts, defined as SQL on Google BigQuery, validated, with its scan size shown – the casts are written once, with a comment on why

Your New Normal

Turn your data into decisions.

Governed data marts give you the clean foundation ML needs to actually work.

  • No AI hallucinations
  • Analyst-governed definitions
  • Every number traces to SQL
Get started free

FAQ

Frequently Asked Questions

Why does SAFE.DATE return an error in BigQuery?

With a string argument BigQuery answers 'SAFE with function date is not supported'. Use SAFE_CAST(x AS DATE) for YYYY-MM-DD values or SAFE.PARSE_DATE with a format string for any other layout.

Does CAST round or truncate when converting a float to an integer?

It rounds, and halfway cases go away from zero: CAST(3.7 AS INT64) is 4, CAST(2.5 AS INT64) is 3 and CAST(-3.5 AS INT64) is -4. To drop the decimal part, apply TRUNC first.

When should I use SAFE_CAST instead of CAST?

When the column comes from outside and some values will be dirty: a spreadsheet import, a form field, an event parameter. Count the rows where the source is not NULL and the SAFE_CAST result is NULL, because SAFE_CAST drops bad values without telling anyone.

What are common errors when using CAST in BigQuery?

'Bad int64 value' for a string that is not a whole number, such as '1,200' or '3.7'. 'Invalid date' for a string that is not YYYY-MM-DD or a date that does not exist. 'Invalid cast from X to Y' for a pair of types that cannot be converted at all.

How do I convert a string to a date in BigQuery?

CAST(s AS DATE) or SAFE_CAST(s AS DATE) when the string is in YYYY-MM-DD form. For another layout add a FORMAT clause, CAST(s AS DATE FORMAT 'DD/MM/YYYY'), or use PARSE_DATE with a format string.

What is the difference between CAST and SAFE_CAST in BigQuery?

Both convert a value to another data type. CAST stops the whole query with an error when one value cannot be converted. SAFE_CAST returns NULL for that value and carries on.

Who wrote this

Alyona Samovar

Alyona Samovar · Senior Digital Analyst

Alyona Samovar is a Senior Digital Analyst who spent years at OWOX helping enterprise clients design analytics systems, build BigQuery reporting pipelines, and optimize marketing measurement. She specializes in SQL-based analytics, data modeling, and turning raw marketing data into actionable insights. Alyona writes about practical analytics workflows, BigQuery best practices, and data-driven decision-making.