Chrome Manifest V3 설치 실패 (Invalid Manifest): V2 종료 대응 및 0x80040154 해결

확장프로그램 설치가 막히면 자동화·업무툴이 즉시 멈추고, 배포/테스트 파이프라인까지 같이 멈출 수 있습니다.

기술 상황 정의(Environment): Web / Chrome / Extensions / (Windows 환경에서 chrome.exe 실행 포함)

2026 포인트: Manifest V2 수명 종료(EOL) 대응이 “오류 수정”이 아니라 “구조 교체”로 취급되는 시점입니다.

Download error: Invalid Manifest (또는 CRX_REQUIRED_PROOF_MISSING / 0x80040154 같은 코드가 함께 관찰될 수 있음)

결론 요약: 단일 원인은 “Manifest V2 기반 패키지(또는 V3 요구 조건을 충족하지 못한 패키지)”가 최신 정책/로더에서 거절되는 구조 문제입니다.

해결 흐름: 판단 → 분리 → (즉시 코드) → 복구

✅ 바로 적용 (Quick Fix)

관리자 권한으로 터미널(Windows Terminal/PowerShell/CMD)을 실행한 뒤 진행하세요.

BitLocker 등 암호화 드라이브/권한 제한 폴더(예: 다른 사용자 프로필, 회사 보안 폴더, 네트워크 드라이브)에 확장 소스가 있으면 Chrome이 파일 접근에 실패해 “경로는 맞는데도 로드 실패”가 발생할 수 있습니다.

결정 문장: 오류가 반복되면 아래 코드부터 실행한다.

WHY: 원인 규명 전에 “내 로컬 소스는 정상 접근 가능한가 / 패키지 구조가 로더에서 열리는가”를 분리해 생존 조치를 먼저 합니다.

METRIC: 확장프로그램 페이지에서 로드가 성공하거나, 같은 에러가 반복되지 않고 다른 에러로 “형태가 바뀌는지” 확인합니다.

NEXT: 여기서 정상 로드가 되면 “정책/패키지 검증” 문제로 이동하고, 여기서도 Invalid Manifest면 “매니페스트/빌드 산출물”로 바로 이동합니다.

Chrome browser interface showing Invalid Manifest error being resolved by command line script execution
# 관리자 권한 필수 / [PATH]를 실제 폴더 경로로 수정하세요.
# Windows PowerShell 예시 (따옴표 포함 경로 안전 처리)
$env:EXT_PATH = "C:\Your\Extension\Path"

# Chrome 실행 파일 경로는 환경마다 다를 수 있으니 필요 시 수정하세요.
# --disable-extensions-except: 지정 경로 확장만 활성화하여 충돌/정책 영향을 최소화
& "C:\Program Files\Google\Chrome\Application\chrome.exe" `
  --disable-extensions-except="$env:EXT_PATH" `
  --load-extension="$env:EXT_PATH" `
  --user-data-dir="$env:TEMP\chrome-ext-sandbox"

🧩 확인 코드 (Verification)

관리자 권한으로 터미널을 실행한 뒤 진행하세요.

WHY: “서버/스토어 정책”과 “내 산출물(매니페스트/빌드)”을 한 번의 실제 검사로 분리합니다.

METRIC: manifest_version 값이 출력되고, 핵심 필드가 실제로 존재하는지 확인됩니다.

NEXT: manifest_version이 2면 즉시 중단하고 TYPE C(수명 종료) 절차로 이동합니다.

# manifest_version이 2라면 즉시 중단해야 함
# macOS/Linux
cat manifest.json | jq '.manifest_version'

# Windows PowerShell
Get-Content .\manifest.json -Raw | jq '.manifest_version'
# (추가 검증) V3 필수 구조를 빠르게 점검: service_worker / permissions / host_permissions 등
# 값이 null/없음이면 "V3 스캐폴딩/마이그레이션 누락" 가능성이 큼
cat manifest.json | jq '{manifest_version, name, version, background, permissions, host_permissions, action, minimum_chrome_version}'

🧯 복구 코드 (Recovery)

관리자 권한으로 터미널을 실행한 뒤 진행하세요.

WHY: 단순 재시도 대신 “V3 기준으로 스캐폴딩/산출물 구조를 재정렬”해 거절 원인을 제거합니다.

METRIC: 로컬 로드가 되고, 빌드 산출물에 manifest_version 3 및 service worker 구조가 반영됩니다.

NEXT: 복구 후에도 설치가 막히면 로컬 조치를 중단하고(정책/배포채널) 운영 정책으로 관리합니다.

# V3 전용 스캐폴딩/업데이트 예시 (프로젝트에 맞게 도구는 선택)
npx chrome-extension-cli@latest update --v3
# (TYPE C 필수) 기존 의존성 추출 → 신규 환경에 재설치
# 1) 기존 의존성 추출
pip freeze > requirements.txt

# 2) 새 가상환경 생성(임시 생존 조치)
python -m venv .venv
# Windows PowerShell
.\.venv\Scripts\Activate.ps1

# 3) 재설치
pip install -r requirements.txt
# (TYPE C 필수) CI/CD에서 버전 고정 예시 (개념 템플릿)
# 실제 사용 중인 CI에 맞게 런타임/노드 버전과 빌드 커맨드를 고정하세요.
name: build-extension
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 'lts/*'
      - run: npm ci
      - run: npm run build

✅ 발생 증상

Chrome에서 확장프로그램을 설치/로드하는 순간 “Invalid Manifest”로 거절됩니다.

동일 상황에서 CRX_REQUIRED_PROOF_MISSING 또는 0x80040154 같은 코드가 로그/대화상자에 함께 관찰될 수 있습니다.

로컬에서 Unpacked로 로드해도 같은 유형의 거절이 반복되며, 설치가 진행되지 않습니다.

❌ 원인 분석

manifest_version이 2이거나, 3으로 보이더라도 V3 필수 구조가 누락된 산출물이라 로더가 거절합니다.

이 문제는 “다운로드 실패”처럼 보이지만, 실제로는 “패키지 구조 검증 단계에서 중단”되는 형태로 나타납니다.

엔터프라이즈 정책(관리자 정책)이나 보안 폴더 권한이 겹치면 “정상 파일인데도 접근 실패 → 결과적으로 로드 실패”로 증상이 더 강화될 수 있습니다.

🧠 기술적 배경 이해 (감리사 1차 판정 구역)

Manifest V2는 백그라운드 페이지 기반으로 장시간 실행되는 구조를 많이 사용했고, 이는 상시 권한/상시 실행이 결합되기 쉬웠습니다.

Manifest V3는 서비스 워커 중심으로 바뀌면서 “수명(라이프사이클)이 짧고 이벤트 기반”인 형태로 강제되며, 로더가 기대하는 필드와 실행 경계가 달라집니다.

이 변화는 단순한 문법 업데이트가 아니라, “실행 모델(Background Page → Service Worker)”의 교체이므로 기존 확장 산출물이 그대로 통과하기 어렵습니다.

따라서 이 이슈는 장애(Outage)나 일시 오류가 아니라 수명 종료(EOL) 이벤트로 분류하는 것이 안전합니다.

이 구조에서 가장 흔한 함정은 “manifest_version만 3으로 바꿨는데도 계속 거절”되는 경우이며, 실제로는 background.service_worker/permissions/host_permissions/action 등 V3 기본 골격이 맞지 않는 케이스가 많습니다.

결정 문장: 이 경우에는 TYPE C(수명 종료)로 판단한다.

Technical diagram comparing Chrome Manifest V2 background pages and V3 service workers lifecycle

📊 빠른 구분표 (Decision Table)

관찰이 경우에는 A로 판단한다즉시 조치
manifest_version 출력이 2TYPE C: V2 수명 종료Recovery로 V3 스캐폴딩/마이그레이션
manifest_version은 3인데 background/service_worker가 비어있음V3 골격 누락(산출물 문제)빌드/템플릿 재생성 후 로컬 로드
로컬 로드는 되는데 스토어/배포 채널에서만 거절정책/서명/배포 요건 문제로컬 조치 중단 → 배포 정책 점검
암호화/권한 폴더에서만 실패접근 권한/샌드박스 경로 문제TEMP 샌드박스 user-data-dir로 분리

✅ 해결 방법 (WHY / METRIC / NEXT)

결정 문장: A면 Quick-Fix, 아니면 정밀 절차로 이동한다.

1) (정밀) 로컬 로드 샌드박스로 재현 범위 고정

WHY: 정책/기존 프로필/다른 확장 충돌을 제거하고 “내 산출물 자체가 열리는지”를 먼저 확정합니다.

METRIC: 동일 폴더를 로드했을 때 성공/실패가 일관되게 재현됩니다.

NEXT: 샌드박스에서만 성공하면 정책/프로필 이슈로 분기하고, 샌드박스에서도 실패하면 매니페스트/빌드로 분기합니다.

# Windows PowerShell
$env:EXT_PATH = "C:\Your\Extension\Path"
& "C:\Program Files\Google\Chrome\Application\chrome.exe" `
  --user-data-dir="$env:TEMP\chrome-ext-sandbox" `
  --disable-extensions `
  --load-extension="$env:EXT_PATH"

2) (정밀) 매니페스트 핵심 필드 “존재/형태” 검증

WHY: 단순 grep은 오탐이 많아, JSON 파싱으로 “필드가 실제로 존재하고 타입이 맞는지”를 확인해야 합니다.

METRIC: manifest_version, background.service_worker, permissions/host_permissions가 기대 형태로 출력됩니다.

NEXT: manifest_version이 2면 즉시 중단하고, 3인데 필드가 비정상이면 스캐폴딩 업데이트로 이동합니다.

# macOS/Linux
cat manifest.json | jq -e '
  .manifest_version as $v |
  {manifest_version:$v, has_service_worker:(.background.service_worker? != null),
   permissions:(.permissions // []), host_permissions:(.host_permissions // [])}
'

3) (정밀) V3 스캐폴딩으로 구조를 “생성 기반”으로 정렬