Skip to content

Deploy Error Analysis

This content is not available in your language yet.

GitHub Actions 배포 워크플로우 실행 중 TypeScript 컴파일 에러Queue 리소스 부재 에러가 발생했습니다.


1. TypeScript 컴파일 에러 (빌드 단계)

섹션 제목: “1. TypeScript 컴파일 에러 (빌드 단계)”
src/apps/api/index.ts(175,40): error TS2345:
Argument of type 'import(".../src/apps/api/index").Bindings'
is not assignable to parameter of type 'import(".../src/index").Bindings'.
Type 'Bindings' is missing the following properties from type 'Bindings':
SEED_QUEUE, DOMAIN_QUEUE

위치: src/apps/api/index.ts:175, src/apps/api/index.ts:179

원인:

  • src/apps/api/index.ts에 정의된 Bindings 타입에 SEED_QUEUE, DOMAIN_QUEUE가 없음
  • src/index.tsBindings에는 있지만, src/apps/api/index.ts에는 없음
  • 두 파일에서 서로 다른 Bindings 타입을 정의하여 타입 불일치 발생

현재 코드:

src/apps/api/index.ts
export type Bindings = {
// ...
RESEARCH_QUEUE: Queue;
CONTRACT_QUEUE: Queue;
LIVENESS_QUEUE: Queue;
// ❌ SEED_QUEUE, DOMAIN_QUEUE 없음
};
// src/index.ts
export type Bindings = {
// ...
RESEARCH_QUEUE: Queue;
CONTRACT_QUEUE: Queue;
LIVENESS_QUEUE: Queue;
SEED_QUEUE: Queue; // ✅ 있음
DOMAIN_QUEUE: Queue; // ✅ 있음
};

에러 1.2: seed-queue-handlers.ts 타입 에러들

섹션 제목: “에러 1.2: seed-queue-handlers.ts 타입 에러들”
src/lib/queue/seed-queue-handlers.ts(182,11): error TS18048: 'record' is possibly 'undefined'.
src/lib/queue/seed-queue-handlers.ts(182,48): error TS18048: 'record' is possibly 'undefined'.
src/lib/queue/seed-queue-handlers.ts(183,31): error TS18048: 'record' is possibly 'undefined'.
src/lib/queue/seed-queue-handlers.ts(186,27): error TS18048: 'record' is possibly 'undefined'.
src/lib/queue/seed-queue-handlers.ts(188,50): error TS2345:
Argument of type '...' is not assignable to parameter of type
'{ domain_id: string; normalized_domain: string; raw_url: string; }'.
Type 'undefined' is not assignable to type '{ domain_id: string; normalized_domain: string; raw_url: string; }'.
src/lib/queue/seed-queue-handlers.ts(191,27): error TS1361:
'NormalizedDomain' cannot be used as a value because it was imported using 'import type'.
src/lib/queue/seed-queue-handlers.ts(194,24): error TS18048: 'record' is possibly 'undefined'.
src/lib/queue/seed-queue-handlers.ts(197,40): error TS18048: 'record' is possibly 'undefined'.
src/lib/queue/seed-queue-handlers.ts(203,38): error TS18048: 'record' is possibly 'undefined'.
src/lib/queue/seed-queue-handlers.ts(215,14): error TS18048: 'record' is possibly 'undefined'.
src/lib/queue/seed-queue-handlers.ts(229,3): error TS6133: 'country' is declared but its value is never read.
src/lib/queue/seed-queue-handlers.ts(233,23): error TS2532: Object is possibly 'undefined'.

원인 분석:

  1. record possibly undefined: 배열 인덱스 접근 시 타입 가드 없음
  2. NormalizedDomain import type: import type으로 import했지만 값으로 사용
  3. country unused: 함수 파라미터로 선언했지만 사용하지 않음
  4. Object possibly undefined: 옵셔널 체이닝 누락

에러 1.3: seed-orchestrator.ts 미사용 변수

섹션 제목: “에러 1.3: seed-orchestrator.ts 미사용 변수”
src/routes/seed-orchestrator.ts(134,3): error TS6133:
'force' is declared but its value is never read.

원인: force 파라미터를 선언했지만 실제로 사용하지 않음

src/schemas/index.ts(70,3): error TS2300: Duplicate identifier 'SourceInfo'.
src/schemas/index.ts(176,3): error TS2300: Duplicate identifier 'SourceInfo'.

원인:

  • src/schemas/seed.ts에서 SourceInfo export
  • src/schemas/seed-engine.ts에서도 SourceInfo export
  • src/schemas/index.ts에서 둘 다 re-export하여 중복 발생

에러 1.5: seed-engine.ts 미사용 import

섹션 제목: “에러 1.5: seed-engine.ts 미사용 import”
src/schemas/seed-engine.ts(9,1): error TS6192:
All imports in import declaration are unused.

원인: CountryCode, ContentCategory를 import했지만 사용하지 않음


2. Queue 리소스 부재 에러 (배포 단계)

섹션 제목: “2. Queue 리소스 부재 에러 (배포 단계)”
✘ [ERROR] Queue "newsfork-seed-staging" does not exist.
To create it, run: wrangler queues create newsfork-seed-staging

위치: 배포 단계 (wrangler deploy --env staging --minify)

원인:

  • provision_queues 함수가 기존 Queue들만 생성:
    • newsfork-research-${env}
    • newsfork-contract-${env}
    • newsfork-liveness-${env}
    • newsfork-dlq-${env}
  • 새로운 Seed Engine Queue들이 누락:
    • newsfork-seed-${env}
    • newsfork-domain-${env}
    • newsfork-seed-dlq-${env}
    • newsfork-domain-dlq-${env}

현재 코드 (cloudflare-resources.sh):

Terminal window
provision_queues() {
local env="$1"
# 기존 Queue만 생성
create_queue_with_auth "newsfork-research-${env}"
create_queue_with_auth "newsfork-contract-${env}"
create_queue_with_auth "newsfork-liveness-${env}"
create_queue_with_auth "newsfork-dlq-${env}"
# ❌ 새로운 Queue들 누락
}

방안 1: Bindings 타입 통일 (Critical)

섹션 제목: “방안 1: Bindings 타입 통일 (Critical)”

문제: 두 파일에서 서로 다른 Bindings 타입 정의

해결:

  1. src/apps/api/index.tsBindings 타입 제거
  2. src/index.tsBindings 타입을 import하여 사용

수정 내용:

src/apps/api/index.ts
// Before
export type Bindings = {
// ...
RESEARCH_QUEUE: Queue;
CONTRACT_QUEUE: Queue;
LIVENESS_QUEUE: Queue;
};
// After
import type { Bindings } from '../../index'; // ✅ 중앙 정의 사용
// export type Bindings 제거

방안 2: seed-queue-handlers.ts 타입 에러 수정

섹션 제목: “방안 2: seed-queue-handlers.ts 타입 에러 수정”

문제: 배열 인덱스 접근 시 타입 가드 없음

해결:

// Before
for (let i = 0; i < data.records.length; i++) {
const record = data.records[i]; // ❌ possibly undefined
// ...
}
// After
for (const record of data.records) { // ✅ for...of 사용
if (!record) continue; // 타입 가드
// ...
}

문제: import type으로 import했지만 값으로 사용

해결:

// Before
import type { NormalizedDomain } from '../../schemas/domain';
// ...
const validated = NormalizedDomain.safeParse(normalized); // ❌ type을 값으로 사용
// After
import { NormalizedDomain } from '../../schemas/domain'; // ✅ type 제거

2.3 country 파라미터 제거 또는 사용

섹션 제목: “2.3 country 파라미터 제거 또는 사용”

문제: 선언했지만 사용하지 않음

해결:

// Before
function reconstructNormalizedDomain(
record: { domain_id: string; normalized_domain: string; raw_url: string },
country: string // ❌ 사용하지 않음
): NormalizedDomain {
// ...
}
// After
function reconstructNormalizedDomain(
record: { domain_id: string; normalized_domain: string; raw_url: string }
// ✅ country 파라미터 제거 (이미 record.domain_id에 country 정보 포함)
): NormalizedDomain {
// ...
}

문제: 객체가 possibly undefined

해결:

// Before
const urlParts = record.domain_id.split(':');
const authority = urlParts[0] as Authority; // ❌ urlParts[0] possibly undefined
// After
const urlParts = record.domain_id.split(':');
if (urlParts.length < 3) {
throw new Error(`Invalid domain_id format: ${record.domain_id}`);
}
const authority = urlParts[0] as Authority; // ✅ 타입 가드 추가

방안 3: seed-orchestrator.ts 미사용 변수 제거

섹션 제목: “방안 3: seed-orchestrator.ts 미사용 변수 제거”

문제: force 파라미터 선언했지만 사용하지 않음

해결:

// Before
async function listRawFiles(
bucket: R2Bucket,
prefix: string,
force: boolean // ❌ 사용하지 않음
): Promise<R2Object[]> {
// ...
}
// After
async function listRawFiles(
bucket: R2Bucket,
prefix: string
// ✅ force 파라미터 제거 (또는 실제로 사용)
): Promise<R2Object[]> {
// ...
}

또는 force를 실제로 사용:

// force가 true면 .success 파일 체크 스킵
if (!request.force) {
const successPath = `${file.key}.success`;
const exists = await c.env.DATASETS_BUCKET.head(successPath);
if (exists) {
skippedCount++;
continue;
}
}

문제: 여러 파일에서 SourceInfo를 export하여 중복

해결 방안 4-1: 이름 변경 (권장)

seed-engine.tsSourceInfo를 다른 이름으로 변경:

src/schemas/seed-engine.ts
// Before
export const SourceInfoSchema = z.object({ ... });
export type SourceInfo = z.infer<typeof SourceInfoSchema>;
// After
export const DomainSourceInfoSchema = z.object({ ... }); // ✅ 이름 변경
export type DomainSourceInfo = z.infer<typeof DomainSourceInfoSchema>;
// DomainMetadataSchema에서도 수정
export const DomainMetadataSchema = z.object({
// ...
source: DomainSourceInfoSchema.optional() // ✅ 이름 변경
});

해결 방안 4-2: 기존 SourceInfo 재사용

seed-engine.ts에서 기존 SourceInfo를 import하여 사용:

src/schemas/seed-engine.ts
// Before
export const SourceInfoSchema = z.object({ ... });
// After
import { SourceInfo as SeedSourceInfo } from './seed'; // ✅ 기존 것 사용
// 또는 별도 타입으로 확장
export const DomainSourceInfoSchema = SeedSourceInfo.extend({
raw_file_path: z.string(),
record_index: z.number().int().optional()
});

권장: 방안 4-1 (이름 변경) - 명확한 구분

방안 5: seed-engine.ts 미사용 import 제거

섹션 제목: “방안 5: seed-engine.ts 미사용 import 제거”

문제: CountryCode, ContentCategory import했지만 사용하지 않음

해결:

src/schemas/seed-engine.ts
// Before
import { DomainId, DomainCountryCode } from './domain';
import { CountryCode, ContentCategory } from './common'; // ❌ 사용하지 않음
// After
import { DomainId, DomainCountryCode } from './domain';
// ✅ CountryCode, ContentCategory import 제거

방안 6: Queue 생성 스크립트 업데이트 (Critical)

섹션 제목: “방안 6: Queue 생성 스크립트 업데이트 (Critical)”

문제: provision_queues 함수가 새로운 Queue들을 생성하지 않음

해결:

.github/scripts/lib/cloudflare-resources.sh
provision_queues() {
local env="$1"
echo "📬 Provisioning Queues for ${env} environment..." >&2
# ... (기존 코드)
# 기존 Queue들
create_queue_with_auth "newsfork-research-${env}"
create_queue_with_auth "newsfork-contract-${env}"
create_queue_with_auth "newsfork-liveness-${env}"
create_queue_with_auth "newsfork-dlq-${env}"
# ✅ 새로운 Seed Engine Queue들 추가
create_queue_with_auth "newsfork-seed-${env}"
create_queue_with_auth "newsfork-domain-${env}"
create_queue_with_auth "newsfork-seed-dlq-${env}"
create_queue_with_auth "newsfork-domain-dlq-${env}"
echo "✅ Queue provisioning completed" >&2
}

  1. Queue 생성 누락 - 배포 즉시 실패
  2. Bindings 타입 불일치 - TypeScript 컴파일 실패
  1. seed-queue-handlers.ts 타입 에러 - 런타임 에러 가능성
  2. SourceInfo 중복 정의 - 타입 충돌
  1. 미사용 변수/import - 코드 품질 이슈

  • src/apps/api/index.ts: Bindings 타입을 src/index.ts에서 import
  • src/lib/queue/seed-queue-handlers.ts:
    • record possibly undefined → for…of 사용
    • NormalizedDomain import type → import로 변경
    • country 미사용 파라미터 제거
    • 옵셔널 체이닝 추가
  • src/routes/seed-orchestrator.ts: force 파라미터 사용 또는 제거
  • src/schemas/seed-engine.ts:
    • SourceInfo 이름을 DomainSourceInfo로 변경
    • 미사용 import 제거
  • src/schemas/index.ts: 중복 export 제거
  • .github/scripts/lib/cloudflare-resources.sh:
    • provision_queues 함수에 새로운 Queue 생성 추가
    • 4개 Queue 추가: seed, domain, seed-dlq, domain-dlq
  • 로컬 TypeScript 컴파일 확인 (pnpm exec tsc --noEmit)
  • 로컬 빌드 확인 (pnpm dev:local)
  • GitHub Actions 재실행

파일: src/apps/api/index.ts

변경 전:

export type Bindings = {
GH_TOKEN: string;
GH_OWNER: string;
GH_REPO: string;
ENVIRONMENT: string;
CF_ENV: string;
DATA_PATH_PREFIX: string;
DATASETS_BUCKET: R2Bucket;
METADATA_BUCKET: R2Bucket;
METADATA_DB: D1Database;
DOMAIN_KV: KVNamespace;
RESEARCH_QUEUE: Queue;
CONTRACT_QUEUE: Queue;
LIVENESS_QUEUE: Queue;
};

변경 후:

import type { Bindings } from '../../index';
// export type Bindings 제거 - 중앙 정의 사용

2. seed-queue-handlers.ts 타입 에러 수정

섹션 제목: “2. seed-queue-handlers.ts 타입 에러 수정”

파일: src/lib/queue/seed-queue-handlers.ts

주요 수정 사항:

  1. NormalizedDomain import 수정
  2. for…of 루프 사용
  3. 타입 가드 추가
  4. 미사용 파라미터 제거

파일: src/schemas/seed-engine.ts

변경 전:

export const SourceInfoSchema = z.object({ ... });
export type SourceInfo = z.infer<typeof SourceInfoSchema>;

변경 후:

export const DomainSourceInfoSchema = z.object({
raw_file_path: z.string(),
record_index: z.number().int().optional()
});
export type DomainSourceInfo = z.infer<typeof DomainSourceInfoSchema>;

파일: src/schemas/index.ts

변경 전:

export { SourceInfo } from "./seed";
export { SourceInfoSchema, SourceInfo } from "./seed-engine"; // ❌ 중복

변경 후:

export { SourceInfo } from "./seed";
export { DomainSourceInfoSchema, DomainSourceInfo } from "./seed-engine"; // ✅ 이름 변경

파일: .github/scripts/lib/cloudflare-resources.sh

변경 전:

Terminal window
provision_queues() {
local env="$1"
create_queue_with_auth "newsfork-research-${env}"
create_queue_with_auth "newsfork-contract-${env}"
create_queue_with_auth "newsfork-liveness-${env}"
create_queue_with_auth "newsfork-dlq-${env}"
}

변경 후:

Terminal window
provision_queues() {
local env="$1"
# 기존 Queue들
create_queue_with_auth "newsfork-research-${env}"
create_queue_with_auth "newsfork-contract-${env}"
create_queue_with_auth "newsfork-liveness-${env}"
create_queue_with_auth "newsfork-dlq-${env}"
# ✅ Seed Engine Queue들
create_queue_with_auth "newsfork-seed-${env}"
create_queue_with_auth "newsfork-domain-${env}"
create_queue_with_auth "newsfork-seed-dlq-${env}"
create_queue_with_auth "newsfork-domain-dlq-${env}"
}

❌ TypeScript 컴파일 실패 (15개 에러)
❌ 배포 실패 (Queue 부재)
✅ TypeScript 컴파일 성공
✅ Queue 자동 생성
✅ 배포 성공

현재 provision_queues 함수는 환경별로 Queue를 생성하지만, 로컬 개발 환경에서는 어떻게 처리할지 확인 필요:

  • 로컬: wrangler dev --local 시 자동 생성되는지 확인
  • 개발: newsfork-seed-dev, newsfork-domain-dev
  • 스테이징: newsfork-seed-staging, newsfork-domain-staging
  • 프로덕션: newsfork-seed-prod, newsfork-domain-prod

새로운 Queue들의 DLQ도 함께 생성해야 함:

  • newsfork-seed-dlq-${env}
  • newsfork-domain-dlq-${env}

모든 타입 에러를 수정하여 런타임 에러 가능성을 최소화해야 함.


분석 일시: 2026-01-28
에러 타입: TypeScript 컴파일 에러 + 인프라 리소스 부재
심각도: Critical (배포 실패)
해결 난이도: 중간 (타입 수정 + 스크립트 업데이트)