Index and Key Errors

IndexError reports a sequence position outside its valid range, while KeyError reports a missing dictionary or set key. You will trace calculated and nested indexes, inspect exact keys, and choose between required lookups, membership checks, and meaningful defaults.

IndexError and KeyError both report that a lookup found no matching item. They apply to different lookup systems.

A list uses integer positions. The list has three items at indexes 0, 1, and 2, so position 3 raises:

IndexError: list index out of range

A dictionary uses keys rather than positions:

The key "Grace" is absent, so Python raises:

KeyError: 'Grace'

The first diagnostic question is therefore: was the program looking for a sequence position or a dictionary key?

Check an Index Against the Sequence Length

For a sequence of length n, valid positive indexes begin at 0 and end at n - 1.

items = ["a", "b", "c"]

The relationship is:

PropertyValue
len(items)3
valid positive indexes0, 1, 2
final positive indexlen(items) - 1, or 2

The length is a count, not an index. items[len(items)] is one position beyond the final item.

Negative indexes count backward from the end:

IndexSelected item
-1"c"
-2"b"
-3"a"

For this length-three list, -3 through 2 are valid. Both 3 and -4 raise IndexError.

An empty sequence has length zero and no valid index:

Before reading a required first item, decide what an empty sequence should mean for the program. It may require a separate result:

Loop Boundaries Commonly Produce Invalid Indexes

This loop goes one step too far:

range(0, len(items) + 1) produces 0, 1, 2, and 3. The first three lookups succeed, which can make the eventual failure seem less obvious. The last lookup requests items[3].

When the index itself is required, stop at len(items):

The stop value of range() is excluded, so this produces only 0, 1, and 2.

When the index is not needed, iterate over the items directly:

This form expresses the real task and removes the manual boundary entirely.

Find where the boundary is crossed

Run the program and inspect the last index printed before the error. Then remove the extra one from the range stop.

Ready to run.

The temporary output identifies the requested index. Compare it with the sequence length and valid range rather than changing the list blindly.

Trace Where a Calculated Index Came From

The failing lookup may use an index calculated earlier:

The traceback points to scores[position], but the faulty boundary decision appears in position = len(scores). Inspect both:

As with a traceback, separate where the failure appears from where the invalid value originated.

Nested lookups require checking one level at a time:

grid[1] succeeds and produces [6, 8]. The second lookup then requests index 2 from that two-item row, whose valid indexes are 0 and 1. Naming the intermediate value makes the failing level visible:

Slices Clamp Their Boundaries

A single-item lookup requires an existing position:

items[10]

A slice can extend beyond the sequence without raising IndexError:

items[0:10]

Python returns the available part of the sequence. For ["a", "b", "c"], the result is still ["a", "b", "c"].

This behavior does not prove that the boundary is correct. If the program expected ten items but received three, the shorter slice may reveal an earlier data problem. Do not replace an invalid single index with a slice merely to silence an error.

A Dictionary Key Must Match Exactly

Dictionary keys are values, not position numbers:

scores = {"Ada": 8, "Lin": 9}

These lookups ask different questions:

Only "Ada" is present. Dictionaries do not assign an automatic position key of 0, and string keys remain case-sensitive.

When a key is stored in a name, inspect both the requested key and the available keys:

The first two lines provide evidence before the failing lookup.

Choose Whether a Missing Key Is an Error

Square-bracket lookup is appropriate when a key is required:

score = scores["Ada"]

If the key is missing, KeyError exposes incomplete or misspelled data.

When absence is an expected possibility, test membership:

Use .get() when a missing key has a meaningful fallback:

Here, zero accurately means that no attempts have been recorded. A fallback of zero would be misleading for a required exam score, because a missing record and an actual score of zero mean different things.

Calling .get(key) without a fallback returns None for a missing key. If the dictionary can also store None, use key in mapping when the program must distinguish “missing” from “present with the value None.”

A set can also raise KeyError. Removing an absent set item with .remove() raises the error, while .discard() leaves the set unchanged. Choose .remove() when absence indicates a mistake and .discard() when absence is an acceptable state.

Exercise: Find the final positive index

A list has length 5. What is its final valid positive index?

Compute it first, then check your number.

HintSeparate count from position

A length-five list has five positions beginning with zero.

SolutionThe final index is four

The valid positive indexes are 0, 1, 2, 3, and 4. Therefore the final valid positive index is 5 - 1, or 4.

Exercise: Repair the loop boundary

Change the range so the program prints all three items without an error.

Stop before the sequence length

Ready to run.

HintUse the excluded stop value

range(len(items)) stops before the length.

SolutionRemove the extra one

Write for index in range(len(items)):. The range produces 0, 1, and 2, matching the list's valid positive indexes.

Exercise: Locate the failing nested lookup

Which part of this expression raises IndexError?

Failing lookup

Select one choice, then check.

HintName the intermediate row

First evaluate row = grid[1], then consider row[2].

SolutionThe column lookup fails

grid[1] produces [6, 8]. That row has length 2 and valid indexes 0 and 1, so its lookup at index 2 raises IndexError.

Exercise: Preserve a required key

A model configuration must contain "learning_rate". Which lookup best keeps a missing value visible as an error?

Required lookup

Select one choice, then check.

HintDo not hide incomplete configuration

The program should stop if the required key is absent.

SolutionUse square brackets for required data

config["learning_rate"] returns the stored value or raises KeyError. Either outcome is more accurate than silently treating missing configuration as zero or None.

Exercise: Use a meaningful dictionary fallback

Complete the program so a missing student has zero recorded attempts.

Retrieve an expected default

Ready to run.

HintAbsence has a defined meaning here

Use attempts.get(student, 0).

SolutionUse get() with zero as the fallback

Write count = attempts.get(student, 0). Since "Grace" is absent, the method returns 0. It does not insert "Grace" into the dictionary.

Inspect the Lookup and Its Source

When Python reports IndexError or KeyError:

  1. identify whether the lookup uses a sequence position or a key;
  2. print the requested index or key before the failing operation;
  3. for an index, compare it with the sequence length and valid boundaries;
  4. for nested indexing, evaluate and name one level at a time;
  5. for a key, compare its exact value and type with the available keys;
  6. decide whether absence indicates a bug or an expected case with a meaningful alternative.

Do not add a fallback only to make the traceback disappear. A safe lookup must preserve the program's intended meaning. The next lesson introduces narrow try and except blocks for failures that are expected at a program boundary.