執行階段與支援錯誤
適用範圍
標題為「適用範圍」的區段下列條目記錄由執行階段支援層所拋出的例外狀況:降級政策、以 cURL 為後盾的 HTTP 傳輸、韌性斷路器、Security Information and Event Management(SIEM)發送器、render manifest、PDF 檢查,以及混沌工程子系統。
每個 NextPDF 例外狀況都繼承 NextPdfException,後者實作 ContextAwareExceptionInterface 並揭露 getContext(): array 以供結構化的診斷記錄使用。子類別只有在覆寫 getContext() 時才會填充該陣列;基底類別回傳空陣列。本頁有三個例外狀況(DegradedException、CircuitBreakerOpenException 與 InspectException)直接繼承 PHP 的 RuntimeException,並以公開的 readonly 屬性揭露其資料,而非 getContext()。下方每個條目都會具名說明該類別所攜帶的確切屬性或脈絡鍵,取自原始碼。
降級政策
標題為「降級政策」的區段DegradedException
標題為「DegradedException」的區段- 何時被拋出。 當繪製管線遇到一項違反當前降級政策的降級能力時。在
DegradationPolicy::Strict下,任何高影響降級(ComplianceRisk、SemanticLoss或Blocking)都會將它拋出;在DegradationPolicy::Balanced下,只有Blocking影響才會將它拋出。 - 類別。 直接繼承
RuntimeException(而非NextPdfException),因此它不攜帶getContext()。 - 攜帶的資料。 兩個公開的
readonly屬性:$capability(觸發拒絕的Capability值物件,包含其id、status、reason、fallbackTarget與impact)與$policy(拒絕當下生效的DegradationPolicy)。訊息的格式為Feature "<id>" is <status>: <reason> (policy: <policy>)。 - 解法。 檢視
$capability以辨識缺少的功能及其成因。可安裝該能力所需的元件、接受影響較低的組態,或在該降級對使用情境而言可接受時,將政策從Strict放寬為Balanced。呼叫$capability->isAvailable()/isDegraded()來驅動面向使用者的訊息。
HTTP 傳輸
標題為「HTTP 傳輸」的區段這三個例外狀況源自以 cURL 為後盾的 PSR-18 用戶端及其具安全意識的裝飾器。前兩者繼承 NextPdfException,但未覆寫 getContext(),因此其 getContext() 回傳空陣列;診斷資料可透過 PSR-18 的 getRequest() 存取器與鏈結的前一個 throwable 取得。
CurlNetworkException
標題為「CurlNetworkException」的區段- 何時被拋出。 當 HTTP 請求因網路層級的故障而無法完成時:Domain Name System(DNS)解析失敗、連線逾時,或 Transport Layer Security(TLS)交握錯誤。它也是具安全意識的裝飾器在安全拒絕(拒絕 Server-Side Request Forgery、拒絕 DNS-rebinding,或遭拒的重新導向)時所拋出的類別。
- 類別。 實作 PSR-18
Psr\Http\Client\NetworkExceptionInterface。 - 攜帶的資料。
getRequest()回傳失敗的RequestInterface。源頭的傳輸錯誤若存在,會是鏈結的前一個 throwable。getContext()回傳空陣列(基底預設值)。 - 解法。 網路故障可能是暫時性的——若請求具冪等性,可採退避重試。安全拒絕並非暫時性,且必須失敗即關閉:不要重試;應改為更正目標 URL 或 SSRF 政策。請讀取訊息與前一個 throwable 來分辨兩者。
CurlRequestException
標題為「CurlRequestException」的區段- 何時被拋出。 當請求本身因為格式錯誤而無法送出時,例如無效的 URL,或一個在任何網路呼叫之前就未通過 SSRF 驗證的請求。
- 類別。 實作 PSR-18
Psr\Http\Client\RequestExceptionInterface。 - 攜帶的資料。
getRequest()回傳出問題的RequestInterface;底層成因若存在,會是鏈結的前一個 throwable。getContext()回傳空陣列。 - 解法。 這是呼叫端輸入或政策的缺陷,而非暫時性故障。不要原封不動地重試。請修正請求的 URL、標頭或主體,或在目標確屬合法允許時調整 SSRF 允許清單,然後重新發出請求。
TransientHttpException
標題為「TransientHttpException」的區段- 何時被拋出。 於內部,在
SecurityAwareHttpClient中,用來把一個真正暫時性的內層傳輸故障(由內層 PSR-18 用戶端引發的 DNS、連線或逾時)標記為符合有界重試預算的資格。它是裝飾器的重試迴圈唯一認得的可重試類別;未經包裝的例外狀況(裝飾器引發的安全拒絕)會被視為致命。 - 類別。 實作 PSR-18
Psr\Http\Client\NetworkExceptionInterface。標記為@internal——它完全在SecurityAwareHttpClient內被建立與解包,絕不逸出裝飾器。 - 攜帶的資料。
getRequest()回傳失敗的請求。原本的內層傳輸ClientExceptionInterface會被保留為鏈結的前一個 throwable(getPrevious()),並在重試預算用盡後原封不動地重新浮現給呼叫端,因此公開的 PSR-18 合約維持不變。getContext()回傳空陣列。 - 解法。 應用程式碼不會直接攔截此型別。請攔截裝飾器在重試預算耗盡後回傳的、重新浮現的內層例外狀況,並把反覆的暫時性失敗視為上游的可用性問題。
CircuitBreakerOpenException
標題為「CircuitBreakerOpenException」的區段- 何時被拋出。 當處於
CircuitBreakerState::Open狀態的CircuitBreaker在任何下游呼叫之前就快速失敗地拒絕一次呼叫時。它的存在是為了讓呼叫端能區分「遠端服務目前無法連線」(一個暫時性的傳輸故障,值得降級)與「這次呼叫本會耗盡連線池」(快速失敗,未嘗試任何網路)——這是 Public Key Infrastructure(PKI)用戶端所要求的批次拒絕服務緩解措施。 - 類別。 直接繼承
RuntimeException,因此它不攜帶getContext()。 - 攜帶的資料。 兩個公開的
readonly屬性:$breakerName(開啟的斷路器的識別碼)與$secondsUntilHalfOpen(斷路器轉為半開之前所剩的概略冷卻時間)。訊息的格式為Circuit breaker "<name>" is OPEN (cooldown ~<n>s remaining); call rejected fail-fast. - 解法。 不要猛敲斷路器——在重試前至少等待
$secondsUntilHalfOpen,或將該操作降級。並未嘗試任何網路呼叫,因此這不是遠端服務本身失敗的證據;它是保護連線池的反壓。
可觀測性
標題為「可觀測性」的區段SiemEmitterException
標題為「SiemEmitterException」的區段- 何時被拋出。 當 SIEM 事件發送器無法持久化或鏈結一筆記錄時。它揭露檔案系統層級的失敗(
open、lock、seek、write、fflush、read)與雜湊鏈完整性故障(chain:索引順序錯亂、尾端記錄格式錯誤,或 JSON 來回轉換漂移),這些是雜湊鏈事件日誌與 JSON-lines 檔案發送器轉接器所共用的。 - 類別。 繼承
NextPdfException並覆寫getContext()。 - 脈絡鍵。
operation(open、lock、seek、write、fflush、read、chain之一)、path(目標日誌路徑)與detail(人類可讀的細節,例如位元組數或預期對實際的索引)。這些也可透過getOperation()、getPath()與getDetail()取得。訊息的格式為SIEM emitter <operation> failed for <path>: <detail>. - 解法。 這由基礎設施或 SecOps 處理,而非應用程式邏輯。請查驗日誌磁碟的掛載、目錄權限、可用的檔案描述符,以及檔案系統健康狀態。
chain操作失敗代表稽核日誌中有竄改或損毀的訊號,應加以調查,而非悄悄重試。
Render manifest
標題為「Render manifest」的區段RenderManifestException
標題為「RenderManifestException」的區段- 何時被拋出。 當
RenderManifest因結構性、型別或結構描述相容性錯誤而無法建構、反序列化或讀取時。manifest 是一份具版本的公開合約,由每個傳輸(CLI、Laravel 佇列、Symfony、SaaS API)提交,因此格式錯誤或不相容的 manifest 會被直接揭露,而非強行套用預設值。 - 類別。 繼承
NextPdfException並覆寫getContext()。具名建構式會在SPEC-MANIFEST-*命名空間中設定一個穩定的機器可讀代碼:RenderManifestException::shape()→SPEC-MANIFEST-001—RenderManifest::fromArray()期間的形狀或型別錯誤。RenderManifestException::incompatibleVersion()→SPEC-MANIFEST-002— 不相容的主要結構描述版本(無法讀取)。RenderManifestException::missingField()→SPEC-MANIFEST-003— 建構器最終化期間缺少必填欄位。RenderManifestException::unsupported()→SPEC-MANIFEST-004— 一個格式正確的 manifest 參照了當前繪製器無法解析的輸入或範本(例如 URI 輸入或僅限主機的範本引擎)。
- 脈絡鍵。
manifest_code(SPEC-MANIFEST-*識別碼)與reason(人類可讀的失敗描述)。這些也可透過getManifestCode()與getReason()取得。訊息的格式為[<code>] <reason>。 - 解法。 依
manifest_code分支處理。對於SPEC-MANIFEST-001與SPEC-MANIFEST-003,修正 manifest 酬載(更正欄位型別或補上缺少的欄位)。對於SPEC-MANIFEST-002,針對受支援的主要結構描述版本重新產生 manifest,或升級繪製器。對於SPEC-MANIFEST-004,提供當前版本能解析的輸入或範本引擎。
InspectException
標題為「InspectException」的區段- 何時被拋出。 當 PDF 檢查失敗時。
- 類別。 直接繼承
RuntimeException(而非NextPdfException),因此它不攜帶getContext()。 - 攜帶的資料。 兩個公開的
readonly屬性:$inspectCode(INSPECT-*命名空間中的機器可讀代碼)與$retryable(一個布林值,指出呼叫端是否應重試——例如當檢查 sidecar 暫時停擺時)。源頭成因若存在,會是鏈結的前一個 throwable。 - 解法。 依
$inspectCode分支處理特定的失敗類別。當$retryable為true時,採退避重試,因為該失敗預期是暫時性的(例如 sidecar 重啟);當為false時,把輸入或組態當作缺陷,且不要原封不動地重試。
混沌工程
標題為「混沌工程」的區段ChaosReportWriteException
標題為「ChaosReportWriteException」的區段- 何時被拋出。 當
ChaosScenarioRunner::writeReport()無法把彙整後的混沌日報持久化到磁碟時。它是對通用執行階段錯誤的領域具型別替代品,因此呼叫端可攔截特定的「報告磁碟」失敗,而不會把它與情境模擬器本身內部引發的錯誤混為一談(runner 會把那些錯誤擷取為ChaosOutcome欄位)。 - 類別。 繼承
NextPdfException並覆寫getContext()。 - 脈絡鍵。
output_path(runner 嘗試寫入的絕對路徑)。它也可透過getOutputPath()取得。訊息的格式為ChaosScenarioRunner: failed to write report to "<path>". - 解法。 這是報告接收端的寫入端失敗,而非情境本身的失敗。請查驗輸出目錄存在且可寫入,以及磁碟空間充足,然後重新執行報告寫入。混沌結果本身不受影響。
RetrievalUnavailableException
標題為「RetrievalUnavailableException」的區段- 何時被拋出。 當一個檢索端點(例如 Voyage Retrieval Augmented Generation 服務)不可用,且系統選擇退回到僅快取模式或失敗即關閉時。
- 類別。 繼承
NextPdfException並覆寫getContext()。 - 脈絡鍵。
mode(失敗後的運作模式——當結果僅由語意快取供應時為CACHED_ONLY,當請求被完全拒絕且無任何陳舊資料時為FAIL_CLOSED)與endpoint(變得無法連線的端點)。這些也可透過getMode()與getEndpoint()取得。訊息的格式為Retrieval endpoint "<endpoint>" is unavailable; operating in <mode> mode. - 解法。 讀取
mode以了解系統如何降級。在CACHED_ONLY下,結果可能陳舊;端點復原後請重新整理一次。在FAIL_CLOSED下,請求是依設計被拒絕的,必須在端點可連線後重試。在仰賴新鮮的檢索之前,請先恢復端點連線能力(網路、憑證、服務健康狀態)。