파이썬 list indices must be integers 오류, API JSON 응답 구조 확인법

파이썬 API 응답에서 list indices must be integers 또는 string indices must be integers가 나오면 대괄호를 무작정 바꾸기보다, 오류가 난 값의 자료형과 중첩 구조부터 확인해야 합니다. dict는 키로 조회하고 list는 숫자 인덱스로 조회하므로, 실제 응답이 어느 쪽인지 확인하면 키 접근·숫자 인덱스·반복문 중 다음 조치를 고를 수 있습니다.

오류 메시지가 알려 주는 것

다음 코드는 목록을 딕셔너리처럼 접근합니다.

items = ["alpha", "beta"]
print(items["name"])

list의 인덱스는 숫자여야 하는데 문자열 키인 "name"을 사용했기 때문에 list indices must be integers 계열의 오류가 발생합니다. 반대로 문자열을 문자 위치가 아닌 키로 다루면 string indices must be integers가 나타날 수 있습니다. 두 오류 모두 해당 줄의 대괄호 앞 값이 내가 생각한 자료형과 다를 가능성을 먼저 보여 줍니다.

다만 오류 문구만으로 API 전체 구조를 확정할 수는 없습니다. 응답의 최상위 값이 dict인지 list인지, 그리고 그 안쪽 값이 무엇인지 단계별로 확인해야 합니다.

먼저 JSON 파싱 결과의 자료형을 확인합니다

Requests의 response.json()은 응답 본문을 Python 객체로 디코딩합니다. JSON 객체는 보통 dict, JSON 배열은 list로 다뤄지므로, 아래처럼 응답을 받은 직후 자료형과 내용을 확인할 수 있습니다.

import requests

response = requests.get("https://api.example.com/items", timeout=10)
response.raise_for_status()
payload = response.json()

print(type(payload).__name__)
print(payload)

여기서 dict가 출력되면 키로 접근합니다.

item_name = payload["name"]

list가 출력되면 숫자 인덱스로 한 항목을 고르거나 목록을 순회합니다.

first_item = payload[0]

for item in payload:
    print(item)

response.json()이 성공했다는 사실만으로 HTTP 요청이 의도대로 처리됐다고 판단해서는 안 됩니다. 상태 코드 확인은 JSON 구조를 읽기 전에 함께 두는 편이 안전합니다. JSON 디코딩 자체가 실패했다면 이 글의 인덱싱 오류가 아니라 JSON 디코딩 문제일 수 있으므로, 빈 응답·HTML·상태 코드로 파이썬 requests JSONDecodeError를 진단하는 순서를 별도로 확인해 보시면 좋습니다.

중첩된 응답은 단계마다 자료형을 확인합니다

API 응답은 최상위만 보고 판단하기 어렵습니다. 예를 들어 다음과 같이 목록 안에 딕셔너리가 들어 있을 수 있습니다.

payload = {
    "items": [
        {"name": "alpha"},
        {"name": "beta"},
    ]
}

items = payload["items"]       # dict에서 "items" 키로 조회
first_name = items[0]["name"]  # list에서 0번째 dict를 고른 뒤 키로 조회

이 구조에서 items["name"]이라고 쓰면 목록을 딕셔너리처럼 다루게 됩니다. 목록의 각 항목을 처리하려는 목적이라면 인덱스를 억지로 붙이는 대신 반복문을 사용합니다.

for item in payload["items"]:
    print(item["name"])

저라면 운영 코드에서 한 줄에 여러 단계를 몰아 쓰기보다 중간 값을 나누고 자료형을 기록합니다. 어느 단계에서 dict가 list로 바뀌었는지 확인하기 쉬워지고, API 문서의 예시와 실제 응답이 달라진 경우에도 원인을 좁힐 수 있습니다.

문자열 JSON이면 한 번만 파싱합니다

입력 경로에 따라 이미 Python 객체인 값이 오기도 하고 JSON 텍스트 문자열이 오기도 합니다. 문자열 자체를 딕셔너리처럼 접근하면 자료형이 맞지 않습니다. JSON 텍스트를 직접 받은 경우에만 json.loads()로 Python 객체로 변환합니다.

import json

raw = '{"items": [{"name": "alpha"}]}'
payload = json.loads(raw)

for item in payload["items"]:
    print(item["name"])

반대로 response.json()의 반환값처럼 이미 디코딩된 객체에 다시 json.loads()를 적용하면 입력 형태가 맞지 않을 수 있습니다. 파싱 전후의 자료형을 구분하고, 실제 입력이 문자열인지 먼저 확인하는 것이 순서입니다.

비슷한 오류와 구분하는 기준

자료형을 확인한 뒤에는 오류 이름도 함께 구분해야 합니다.

오류 먼저 확인할 것 일반적인 원인
list indices must be integers 대괄호 앞 값의 type() list에 문자열 키를 사용함
string indices must be integers 값이 문자열인지 여부 문자열을 dict처럼 접근함
KeyError 키 이름과 실제 응답 키 dict에 없는 키를 조회함
IndexError 목록의 길이와 인덱스 list 범위를 벗어남
JSON 디코딩 오류 원문이 유효한 JSON인지 JSON 텍스트 파싱 실패

dict에 없는 키를 조회하면 KeyError, 목록 범위를 벗어나면 IndexError가 발생합니다. 따라서 모든 오류를 payload[0]으로 고치려 하지 말고, 현재 값의 자료형과 필요한 접근 방식이 일치하는지 먼저 판단해야 합니다.

운영 코드에 적용할 확인 순서

다음 순서로 확인하면 수정 방향이 비교적 명확해집니다.

  1. 오류가 난 줄에서 대괄호 앞 변수의 type()과 실제 구조를 확인합니다.
  2. 입력이 JSON 문자열이면 한 번 파싱하고, 이미 Python 객체면 다시 파싱하지 않습니다.
  3. dict에는 실제 키를 사용하고, list에는 숫자 인덱스 또는 반복문을 사용합니다.
  4. 중첩 응답은 각 단계의 자료형을 나누어 확인합니다.
  5. 키 누락, 빈 목록, 응답 계약 변경처럼 정상 응답이 아닌 경우의 처리 방식을 정합니다.

자동화에서는 예외를 무조건 숨기는 것보다, 실패한 단계와 응답의 안전한 요약을 로그로 남기는 편이 재발 방지에 도움이 됩니다. 비밀번호나 토큰이 포함될 수 있는 원문 전체를 그대로 기록하는 방식은 피해야 합니다.

결국 이 오류의 핵심은 대괄호 문법 자체가 아니라 값의 shape와 접근 방식이 어긋난 데 있습니다. type()으로 현재 값을 확인하고, API 문서가 설명하는 구조와 실제 응답을 비교한 뒤 파싱·키 접근·인덱스·반복문 중 맞는 방법을 선택하면 됩니다.

출처

Leave a Comment