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.
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
CASTwhen a failed conversion means the data is broken and you want to know: a pipeline step, a test, a column you control. - Use
SAFE_CASTwhen 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
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'toINT64isNULL. Cast toFLOAT64orNUMERICfirst. - An empty string is not zero. It is
NULLafterSAFE_CASTand an error afterCAST. - A hex string with the
0xprefix 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.
OWOX Data Marts
See your first report built in real time. 15 minutes.
- Connect your data warehouse
- Pick your metrics
- Get a live Google Sheets report
In the time it takes to write a ticket. Then imagine never writing that ticket again.
Book a DemoWe'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
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
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
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
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
“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
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.

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
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.
