TryBugHunt

Type errors: when a number is secretly a string

Totals that concatenate, sorts that put 10 before 9, comparisons that refuse to run.

65 free challenges37 Python28 JavaScript

What is a type error?

A value is not the type the code assumes. Python usually raises immediately; JavaScript usually converts silently and gives a wrong answer, which is worse because nothing tells you anything went wrong.

Why it happens

Data crossing a boundary loses its type. Form fields, JSON, query strings and CSV files all arrive as text. JSON object keys are always strings even when they look like numbers. JavaScript's + means addition or concatenation depending on its operands, and its default sort compares elements as strings.

How to recognise it

  • A total is a string of digits stuck together rather than a sum.
  • Sorting puts 10 before 9 — string ordering, not numeric.
  • KeyError on a key you can see in the printed dict (it is "1", not 1).
  • In Python 3, / always returns a float, so it can never be an index.

Error guides caused by this pattern

All error guides →

In-depth guides for common exceptions and runtime errors triggered by type errors, with working fixes and real-world examples:

How to fix it

Convert once, at the boundary where data enters, rather than scattering int() and Number() through your logic. Use === over == in JavaScript so type mismatches fail loudly. When a value surprises you, print its type before you print its value.

Breaks vs Works Example

Breaks

// JavaScript: string concatenation instead of addition
const total = inputField.value + 10; // '20' + 10 = '2010'

Works

// JavaScript: explicit numeric conversion at input boundary
const total = Number(inputField.value) + 10; // 20 + 10 = 30

💡 Form values, URL query params, and JSON strings must be parsed at boundaries.

Practise type errors

Working code with one bug in it. Find it, fix it in the browser, and see the explanation. No account needed.

javascriptEasy
Cart total shows "01020" instead of 30

calculateTotal(items) adds up item.price for every item. The prices arrive as text, like "10". Example: prices "10" and "20" → 30.

Type error

javascriptEasy
Query string literal null value treated as valid string

extract_referrer_source(queryString) returns referrer parameter ref, falling back to "organic" if ref is missing, "null", or "undefined". Example: extract_referrer_source("ref=null") → "organic".

Type error

javascriptEasy
Digit sum gives "0123" instead of 6

digitSum(n) adds up the digits of a number. Example: digitSum(123) → 6.

Type error

pythonEasy
Counting digits crashes on a number

count_digits(n) returns how many digits a positive whole number has. Example: count_digits(12345) → 5.

Type error

pythonEasy
Sorting objects by key with None raises TypeError

sort_users_by_priority(users) sorts users by numeric priority ascending, placing None priorities at the end. Example: sort_users_by_priority([{"id": 1, "priority": None}, {"id": 2, "priority": 5}]) → [{"id": 2, "priority": 5}, {"id": 1, "priority": None}].

Type error

javascriptEasy
Query parameter false string converted to boolean evaluates to true

is_admin_query_active(queryParams) checks if isAdmin is true, handling both boolean and string "true" values. Example: is_admin_query_active({ isAdmin: "false" }) → false.

Type error

pythonEasy
Appending sublist of roles nests array instead of extending

add_granted_roles(roles, new_roles) adds all items from new_roles to roles as flat elements. Example: add_granted_roles(["user"], ["admin"]) → ["user", "admin"].

Type error

javascriptEasy
Adding toFixed result to number performs string concatenation

calculate_bill_with_tax(subtotal, taxRate) returns the sum of subtotal and rounded tax. Example: calculate_bill_with_tax(100, 0.15) → 115.

Type error

pythonEasy
Middle item lookup crashes with TypeError

middle_item(items) returns the item in the middle of the list. Example: middle_item([1, 2, 3]) → 2.

Type error

pythonEasy
Single quoted dictionary string raises JSONDecodeError

parse_python_dict_payload(payload_str) parses a Python literal dictionary string with single quotes into a dict. Example: parse_python_dict_payload("{'id': 1}") → {"id": 1}.

Type error

pythonEasy
Single element tuple without comma evaluates to integer

wrap_in_tuple(val) wraps val in a tuple and returns the type name "tuple". Example: wrap_in_tuple(42) → "tuple".

Type error

pythonEasy
PIN builder crashes on a list of digits

build_pin(digits) joins a list of digits into a PIN. Example: build_pin([1, 2, 3, 4]) → "1234".

Type error

javascriptEasy
Empty cart tax calculation raises TypeError in reduce

calculate_cart_tax(cartItems) sums the tax amount across all items in a cart, returning 0 if the cart is empty. Example: calculate_cart_tax([]) → 0.

Type error

pythonEasy
Four digit year string raises ValueError with lowercase y format

parse_log_timestamp(date_str) parses a "YYYY-MM-DD" date string and returns formatted output. Example: parse_log_timestamp("2026-11-02") → "2026-11-02".

Type error

pythonEasy
AI Attempt: The palindrome checker

An AI assistant wrote this to check if a word reads the same backwards, ignoring capitals. Example: is_palindrome("Racecar") → True, is_palindrome("hello") → False.

Type error

javascriptEasy
Parsing string numbers with array map returns NaN and binary

parse_number_ids(ids) converts an array of string numbers into integers. Example: parse_number_ids(["10", "10", "10"]) → [10, 10, 10].

Type error

javascriptEasy
Malformed token string causes JSON parse to throw SyntaxError

safe_parse_token_payload(rawToken) parses a JSON token payload string, returning null if the string is invalid JSON. Example: safe_parse_token_payload("invalid{") → null.

Type error

pythonEasy
Exam percentage always comes out as 0

percent_score(correct, total) returns a whole-number percentage. Example: percent_score(3, 4) → 75.

Type error

pythonEasy
Reversing list in place with reverse method returns None

get_reversed_audit_log(logs) returns a new list with logs in reverse chronological order. Example: get_reversed_audit_log(["a", "b"]) → ["b", "a"].

Type error

javascriptEasy
Array unshift returns new length instead of prepended array

prepend_item(items, newItem) returns an array with newItem prepended at the beginning. Example: prepend_item(["b"], "a") → ["a", "b"].

Type error

pythonEasy
Looking up integer user ID in loaded JSON raises KeyError

lookup_cached_score(cache_json, user_id) retrieves the score for integer user_id from serialized JSON cache data. Example: lookup_cached_score('{"1": 95}', 1) → 95.

Type error

pythonEasy
3 tickets at 20 gives "333…" instead of 60

tickets_total(count_text, price) works out the cost of a booking. The ticket count comes from a form as text. Example: tickets_total("3", 20) → 60.

Type error

pythonEasy
Capitalizing a name crashes with TypeError

capitalize_name(name) makes the first letter a capital and leaves the rest. Example: capitalize_name("asha") → "Asha".

Type error

javascriptEasy
Parsing number with trailing letters produces partial integer

parse_strict_integer(valStr) parses a string strictly as an integer, returning NaN if it contains non-numeric trailing characters. Example: parse_strict_integer('100px') → NaN.

Type error

javascriptEasy
Token expiry check marks future tokens as expired

is_token_expired(payload, currentTimestampMs) returns true if the JWT payload expiration (in Unix seconds) has passed relative to currentTimestampMs (in milliseconds). Example: is_token_expired({ exp: 1730592000 }, 1730591000000) → false.

Type error

pythonEasy
Timedelta total seconds called as attribute raises AttributeError

get_duration_in_seconds(days, hours) returns the total duration in seconds as an integer. Example: get_duration_in_seconds(1, 2) → 93600.

Type error

pythonEasy
Passing list of types to isinstance raises TypeError

is_valid_numeric_or_string(val) returns True if val is an int, float, or str. Example: is_valid_numeric_or_string(42) → True.

Type error

pythonEasy
Sum function with string elements raises TypeError

concatenate_words(words) concatenates a list of words into a single string. Example: concatenate_words(["code", "review"]) → "codereview".

Type error

javascriptEasy
Iterating array with for in treats indices as string concatenation

sum_numbers_in_list(numbers) calculates the sum of all numbers in an array. Example: sum_numbers_in_list([10, 20, 30]) → 60.

Type error

javascriptEasy
Checking if order quantity is integer fails on string numbers

is_valid_quantity(qty) returns true if qty represents a positive whole integer, accepting both numbers and numeric strings. Example: is_valid_quantity("5") → true.

Type error

pythonEasy
Setting "False" still turns the switch on

parse_flag(text) reads a setting written as "true" or "false", in any case, and returns True or False. Example: parse_flag("False") → False.

Type error

pythonEasy
Price parser rejects prices with cents

parse_price(text) turns a typed price into a number. Example: parse_price("3.50") → 3.5, parse_price("12") → 12.

Type error

pythonEasy
Checking length of filter object raises TypeError

count_active_users(users) returns the count of users where active is True. Example: count_active_users([{"active": True}, {"active": False}]) → 1.

Type error

pythonEasy
Reversed text shows <reversed object at 0x…>

reverse_text(text) returns the text backwards. Example: reverse_text("hello") → "olleh".

Type error

pythonEasy
Age next year crashes on form input

age_next_year(age_text) gets an age typed into a form, as text, and returns next year's age as a number. Example: age_next_year("20") → 21.

Type error

javascriptEasy
Empty string input coerced to zero by Number constructor

parse_user_age(ageStr) parses an age string into a number, returning null for empty or non-numeric strings. Example: parse_user_age("") → null.

Type error

pythonEasy
Subclass check with isinstance accepts instances instead of class

verify_is_exception_class(cls_obj) returns True if cls_obj is a class inheriting from Exception, returning False for instances or non-classes. Example: verify_is_exception_class('ValueError') → False.

Type error

pythonEasy
Boolean argument passes integer check and increments to two

increment_integer_only(val) increments val by 1 only if val is a mathematical integer, returning None for booleans and other types. Example: increment_integer_only(True) → None.

Type error

pythonEasy
Average of 1 and 2 comes out as 1

average(nums) returns the average of the numbers, including any decimal part. Example: average([1, 2]) → 1.5.

Type error

pythonEasy
Price label crashes on a number

format_price(amount) returns the amount with a dollar sign. Example: format_price(5) → "$5".

Type error

pythonEasy
Subclass check with type identity fails for inherited classes

is_base_handler(handler_name) returns True if handler is an instance of BaseHandler or its subclasses. Example: is_base_handler("auth") → True.

Type error

pythonEasy
Sorting list with sort method returns None instead of list

get_sorted_scores(scores) returns a new list containing scores in ascending order. Example: get_sorted_scores([3, 1, 2]) → [1, 2, 3].

Type error

javascriptEasy
Correct PIN is rejected

checkPin(typed, saved) compares a PIN typed in a form, as text, with a saved PIN stored as a number. Example: checkPin("1234", 1234) → true.

Type error

javascriptEasy
Counting positives crashes on the first one

countPositives(nums) counts the numbers above zero. Example: countPositives([3, -1, 4]) → 2.

Type error

javascriptEasy
Helper adding role returns array length instead of array

add_user_role(roles, newRole) appends newRole to roles and returns the updated array. Example: add_user_role(["user"], "admin") → ["user", "admin"].

Type error

javascriptHard
Type checker says null is an object

describeType(value) names the type of a value. It returns "null" for null and "object" for real objects. Example: describeType(null) → "null".

Type error

javascriptHard
Two identical records counted as different

countUnique(records) counts records with different contents. Two records with the same fields count once. Example: countUnique([{ id: 1 }, { id: 1 }]) → 1.

Type error

pythonHard
Lookup says KeyError: 1, but 1 is right there

total_for_ids(counts, ids) adds up the counts for the given ids. counts comes from JSON, so its keys are text, like {"1": 10}. The ids are numbers. Example: total_for_ids({"1": 10, "2": 20}, [1, 2]) → 30.

Type error

pythonMedium
Price in cents comes out one cent short

to_cents(price_text) turns a price like "19.99" into whole cents. Example: to_cents("19.99") → 1999.

Type error

javascriptMedium
Vote total shows "034" instead of 7

countVotes(entries) adds up the votes of every entry. The votes arrive as text, like "3". Example: votes "3" and "4" → 7.

Type error

pythonMedium
Comparing form values to a number crashes

count_above(values, threshold) counts the values bigger than threshold. The values arrive from a form as text. Example: count_above(["1", "5", "10"], 3) → 2.

Type error

pythonMedium
Update check thinks 10.0 is older than 9.4

is_newer(version, current) returns True if version is a later release. Example: is_newer("10.0", "9.4") → True.

Type error

pythonMedium
Role check lets "adm" through

can_edit(role) returns True only for roles in the allowed list, which has just "admin". Example: can_edit("admin") → True, can_edit("adm") → False.

Type error

javascriptMedium
Prices over 1,000 come out as 1

parsePrice(text) reads a price that may have commas, like "1,250.50". Example: parsePrice("1,250.50") → 1250.5.

Type error

pythonMedium
Pages needed comes back as 2.5

pages_needed(items, per_page) returns how many pages are needed, counting a partly full last page. Example: pages_needed(10, 4) → 3.

Type error

javascriptMedium
map(parseInt) turns "10" into NaN and 2

parseAll(strings) turns a list of number strings into numbers. Example: parseAll(["10", "10", "10"]) → [10, 10, 10].

Type error

javascriptMedium
Sorting puts 9 after 100

sortNumbers(nums) returns the numbers from smallest to largest. Example: sortNumbers([10, 9, 100, 1]) → [1, 9, 10, 100].

Type error

javascriptMedium
Empty age field passes validation

isValidAge(input) checks the age typed in a form. A blank field is not valid. Example: isValidAge("25") → true, isValidAge("") → false.

Type error

javascriptMedium
Array sum returns 0012

sumAll(nums) adds up an array of numbers. Example: sumAll([5, 6, 7]) → 18.

Type error

pythonMedium
Adding up "4,5,6" crashes

csv_total(line) adds up numbers separated by commas. Example: csv_total("4,5,6") → 15.

Type error

javascriptMedium
1.5 + 2.5 comes out as 3

sumPrices(prices) adds up prices that arrive as text. Example: sumPrices(["1.5", "2.5"]) → 4.

Type error

pythonMedium
Highest score picks "9" over "10"

highest(values) returns the biggest number from a list of numbers written as text. Example: highest(["9", "10", "2"]) → "10".

Type error

pythonMedium
Counting map pins crashes on [x, y] points

count_unique_points(points) counts the different map pins. Each pin is [x, y]. Example: count_unique_points([[0, 0], [1, 2], [0, 0]]) → 2.

Type error

javascriptMedium
Identical lists are reported as different

sameOrder(a, b) returns true when two arrays hold the same values in the same order. Example: sameOrder([1, 2], [1, 2]) → true.

Type error

javascriptMedium
Zero counter also counts "" and false

countZeros(values) counts the entries that are the number 0. Example: countZeros([0, "", false, 0]) → 2.

Type error

Stuck on your own code?

Paste it into the visualizer and watch it run line by line, with every variable at every step. Free, and it runs in your browser.

Other bug patterns