<!-- canonical: https://docs.axelabs.ai/ops/troubleshooting -->
<!-- source: content/ops/troubleshooting.mdx -->

---
title: 운영자 문제 해결
description: 직원이 보고하는 문제 분류 + 운영자 측 진단 단계.
---

# 운영자 문제 해결

직원이 "frame 안 됩니다" 라고 호출 왔을 때 진단 순서.

## Step 1 — 외부 health

```bash
curl -sI https://axe.axelabs.ai/frame/health
# 200 OK 인지 확인
```

200 OK 안 나오면:
- → cloudflared 죽음? `docker ps | grep axelabs-tunnel`
- → frame 자체 죽음? `docker ps | grep frame-mcp`
- → Cloudflare 측 장애? Cloudflare status page 확인

## Step 2 — protected-resource 메타데이터

```bash
curl -sS https://axe.axelabs.ai/frame/.well-known/oauth-protected-resource | python3 -m json.tool
```

기대 응답:
```json
{
  "resource": "https://axe.axelabs.ai/frame/mcp",
  "authorization_servers": [
    "https://login.microsoftonline.com/122fb574-7efa-476a-95b6-bee81bce2cce/v2.0"
  ],
  "scopes_supported": [...],
  "bearer_methods_supported": ["header"]
}
```

`resource` 가 다르면 → customers.yaml 의 public_domain 확인.
`authorization_servers` 의 tenant_id 가 customers.yaml 와 다르면 → 환경변수 갱신.

## Step 3 — frame 로그

```bash
docker logs --since 10m frame-mcp-blue 2>&1 | grep -v 'health\|/ready' | tail -30
```

패턴:
- `POST /frame/mcp 401 Unauthorized` 만 보임 → Bearer 안 들어옴, claude.ai 측 또는 Microsoft 측 문제
- `POST /frame/mcp 200 OK` + tool 호출 → 정상
- `INVALID_TOKEN` / `OIDC_UNAVAILABLE` / `EntityNotAuthorizedError` → 각각 다른 진단

## Step 4 — 직원 측 정보 수집

직원에게 요청:

1. claude.ai/customize/connectors 페이지의 Frame connector 상태 (Connected / Disconnected / Authorization failed)
2. 오류 메시지 전문 (스크린샷)
3. 브라우저 주소창의 전체 URL (특히 `error_code=`, `entra_aadsts_code=`, `entra_trace_id=`)
4. 본인 회사 이메일

## Step 5 — Microsoft sign-in log

Azure portal → Microsoft Entra ID → Monitoring → Sign-in logs:
- 직원의 trace_id 또는 시간 + 이메일로 필터
- Sign-in error code (AADSTS XXX) 확인
- Failure reason

## Step 6 — 분류

| 증상 | 원인 후보 | 해결 |
|---|---|---|
| AADSTS700016 | client_id 오타 또는 misconfig | customers.yaml 확인 |
| AADSTS9010010 | resource ≠ scope prefix | Application ID URI ↔ scope 일치 확인 |
| AADSTS7000218 | secret 없음 + public client flow off | secret 발급 + claude.ai 입력 |
| AADSTS65001 | consent 안 함 | 직원이 consent 화면에서 Accept |
| mcp_client_invalid | aud 검증 실패 (v2 토큰) | manifest accessTokenAcceptedVersion = null |
| Couldn't reach MCP server | URL 오타 또는 frame 죽음 | Step 1 |
| EntityNotAuthorizedError | customers.yaml 매핑 누락 | user_entity_map 에 추가 + frame 재기동 |
| 권한 부족 | 직원의 scope 부족 | 권한 상승 결정 + customers.yaml |

## 자주 발생하는 운영자 측 실수

| 실수 | 증상 | 대응 |
|---|---|---|
| customers.yaml 수정 후 frame restart 안 함 | YAML 변경 안 반영 | `docker compose restart frame-mcp-blue frame-mcp-green` |
| 환경변수 변경 후 `--force-recreate` 안 함 | env 안 읽음 | `docker compose up -d --force-recreate` |
| Application ID URI cleanup (삭제) | AADSTS500011 | 복원 후 propagation 대기 |
| Bitwarden secret 평문 평이메일 전송 | 노출 | secret rotation |
| Cloudflare DNS A record 누락 | DNS 미해석 | record 추가 + propagation 대기 |
| 운영자 콘솔 stale | dashboard 옛 정보 | `axe console rebuild` |

## 진단 cheat sheet

```bash
# 인프라 health
axe health &lt;customer&gt;

# Cloudflare tunnel
docker ps | grep tunnel
docker logs --tail 50 axelabs-tunnel

# Frame
docker ps | grep frame
docker logs --since 5m frame-mcp-blue | grep -v health
docker exec frame-mcp-blue python -m frame.cli integrity-check --entity <e>

# customers.yaml
cat /Users/axe/.axe/customers.yaml | grep -A 5 user_entity_map

# Microsoft Entra
# (Azure portal 또는 Microsoft Graph CLI)
```

## Escalation

위로도 안 풀릴 때:

1. 운영자 본인 → 진단 + Slack `#alerts` 노트
2. customer admin 에게 통지 (영향 범위 안내)
3. 직원에게 임시 우회 (workaround 가능하면 제공)
4. 본격 디버깅 시간 잡기 (보통 1시간 내 해결, 안 풀리면 휴식 후 fresh 접근)

## 학습 — 이슈 사후 기록

해결 후 [DECISIONS](/ops/decisions) 또는 함정 모음에 추가:
- 새로운 함정 발견했으면 표에 add
- 기존 함정 변형이면 기존 항목 update
- 향후 동일 사건 재발 시 참조 가능
