본문으로 건너뛰기
cccskills
무료GitHub에 공개

fastly-compute-native-test-linker-failure

Fix Fastly Compute Rust crate `cargo test` failures with "ld: symbol(s) not found" errors for Fastly SDK symbols like `_version_set`, `_body_new`, `_req_send` on native host builds. Use when: (1) `cargo test` on a Fastly Compute crate fails at link time with errors mentioning libfastly and symbols with names like `fastly::http::response::handle::...`, (2) You added a `#[cfg(test)]` module to a file in a Fastly Compute binary crate and the tests never seem to run or fail to link, (3) Existing `#[cfg(test)]` modules in src/main.rs or its sibling modules appear dead despite being present in the source tree, (4) `cargo test --lib` works but `cargo test` fails.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

연동 도구Vercel
설치 방법 보기

포함된 파일(1)

  • SKILL.md9.1 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Fastly Compute native test linker failure

Problem

Fastly Compute Rust binaries link against libfastly, which provides FFI symbols that only exist when targeting wasm32-wasip1. On a native host (macOS, Linux x86_64, Linux arm64), the FFI symbols are absent, so linking a test binary for the Fastly Compute crate fails with errors like:

"_version_set", referenced from:
    fastly::http::response::handle::ResponseHandle::set_version::h234bdb33f8878476 in libfastly-XXXX.rlib
"_body_new", referenced from:
    fastly::http::body::Body::new::hYYYY in libfastly-XXXX.rlib
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1
error: could not compile `fastly-blossom` (bin "fastly-blossom" test)

The error appears during cargo test even if none of your tests actually call Fastly SDK code — cargo still tries to compile and link the entire binary as a test target.

This has a nasty consequence: any #[cfg(test)] mod tests { ... } block inside a file compiled into the binary crate is effectively dead code. It never runs via cargo test because cargo can't link the test binary. Developers add tests, the compiler accepts them, they're visible in the source tree — but they never execute. Tests that were meant to regression-guard behavior silently become documentation that rots.

Context / Trigger Conditions

  • Fastly Compute Rust project with fastly = "0.11.x" (or similar) as a dependency
  • The crate has both src/main.rs and src/lib.rs OR only src/main.rs
  • cargo test fails at link time with _version_set / _body_new / _req_send undefined
  • cargo check --target wasm32-wasip1 succeeds
  • cargo check (native) succeeds (library code compiles, just can't link the binary)
  • You added tests in src/admin.rs, src/blossom.rs, src/metadata.rs, or any file that's mod-included from src/main.rs but NOT from src/lib.rs

Root cause

Fastly's Rust SDK (fastly crate) is designed exclusively for wasm32-wasip1. Its public API calls unsafe FFI functions (_version_set, _req_send, _body_new, etc.) that the Fastly Compute runtime provides at execution time inside the POP. On a native host, the rustc compiler still compiles the library crate, but the linker can't resolve those FFI symbols because libfastly-native doesn't exist.

cargo test for a mixed lib+bin crate links two artifacts: the library test binary AND the binary test binary (the main executable with tests enabled). The library test binary can avoid the SDK symbols if lib.rs doesn't import them transitively. The binary test binary can't, because main.rs wires the whole Fastly Compute runtime.

Solution

Structure your crate as lib + bin, and put all testable logic in lib

  1. Create src/lib.rs if it doesn't exist:
// src/lib.rs — library target, testable natively
pub mod admin_sweep;   // pure logic, no Fastly SDK
pub mod classifiers;   // pure logic, no Fastly SDK
pub mod parsers;       // pure logic, no Fastly SDK
  1. Put any module you want to unit-test in a separate file that does NOT import Fastly SDK types, and expose it via pub mod in lib.rs:
// src/admin_sweep.rs — pure logic, testable natively
pub enum StuckAction { SkipNotStuck, SkipTooRecent, MarkComplete, ResetPending }

pub fn classify_stuck_record(
    is_processing: bool,
    uploaded_iso: &str,
    threshold_iso: &str,
    hls_present: bool,
) -> StuckAction { /* ... */ }

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn skip_not_stuck_when_status_is_not_processing() { /* ... */ }
}
  1. In src/main.rs, also declare the module so the binary can use it:
mod admin_sweep;  // same file, compiled twice — once for lib, once for bin
  1. The handler in an admin.rs (or wherever) that DOES use Fastly SDK types extracts primitives from SDK types and calls the pure classifier:
// src/admin.rs (part of the bin, uses Fastly SDK types like Request/Response)
pub fn handle_sweep(req: Request) -> Result<Response> {
    let is_processing = meta.transcode_status == Some(TranscodeStatus::Processing);
    let action = crate::admin_sweep::classify_stuck_record(
        is_processing, &meta.uploaded, &threshold_iso, hls_present,
    );
    // ... match on action, make SDK-level calls ...
}
  1. Run tests with:
cargo test --lib

Not cargo test (which tries to link the bin). --lib only builds and runs the library test binary, which can link because none of its code touches Fastly SDK symbols.

Do NOT depend on crate internals from the lib module

Your lib-exposed module must NOT transitively import anything that touches the Fastly SDK. Common traps:

  • use crate::blossom::BlobMetadata; — if blossom.rs is in the binary crate and uses fastly::Request, importing BlobMetadata drags SDK symbols into the lib build. Solution: pass raw primitives (Option<TranscodeStatus>, &str, etc.) across the boundary, not full SDK-aware structs.
  • use crate::storage::current_timestamp; — if storage.rs calls fastly::kv_store::*, same problem. Duplicate the helper in admin_sweep.rs or extract it to a third SDK-free module in lib.rs.

Treat lib.rs as a clean-room: only pure Rust, no SDK types, no platform-specific I/O.

Verify

cargo check --target wasm32-wasip1  # must still succeed (bin compiles for deploy)
cargo test --lib                     # must run and pass (tests exercise pure logic)

You can also add to CI:

- run: cargo test --lib
- run: cargo check --target wasm32-wasip1

cargo test (no flags) will still fail on this project; that's expected and unavoidable. Document it in README or CONTRIBUTING so contributors don't waste time on it.

Verification

After applying this pattern:

  • cargo test --lib runs your new tests and they execute (pass or fail, but they RUN)
  • cargo check --target wasm32-wasip1 still produces a deployable WASM
  • Existing #[cfg(test)] mod tests blocks in binary-only files (admin.rs, etc.) are still dead; consider migrating them into lib-exposed modules or deleting them if the behavior they test can be moved

Example

In the Divine Blossom repo, the Fastly Compute crate (src/main.rs) had #[cfg(test)] modules in src/delete_policy.rs, src/error.rs, src/auth.rs, src/blossom.rs, and src/metadata.rs. None of these ran via cargo test — lib.rs only exposed resumable_complete. Attempting to add tests to src/admin.rs failed at link time.

The fix was to create src/admin_sweep.rs with zero dependencies on the rest of the crate (no use crate::blossom, no use crate::storage), add pub mod admin_sweep; to lib.rs, and have the tests live there. The handler in src/admin.rs (binary-only) extracts four primitives from BlobMetadata before calling the pure classifier.

Result: cargo test --lib now runs 11 tests (7 new + 4 pre-existing from resumable_complete). The wasm32-wasip1 build still produces a valid Fastly Compute binary. The binary-only #[cfg(test)] modules are still dead, but the logic that matters is now covered.

Notes

  • This is a structural constraint imposed by the Fastly SDK's FFI design, not something Fastly will "fix" — the SDK crate has to provide those symbols somehow, and the runtime is wasm.
  • Fastly's own examples tend to avoid tests entirely, which is why this trap is widespread.
  • The same pattern applies to any Rust crate that targets a specific platform via FFI symbols provided by a host runtime: Cloudflare Workers (worker-rs), Vercel Edge (@vercel/edge), some embedded HAL crates, etc. The "put pure logic in lib, keep SDK calls in bin" pattern generalizes.
  • If you're starting fresh, consider making your Fastly Compute crate a library-only crate with a tiny src/main.rs that just calls lib::run(). Then everything is in the lib by default and there's no bin/lib split to worry about. This is the cleanest structure.
  • rust-analyzer and IDE tooling will still happily analyze and type-check the #[cfg(test)] modules in binary-only files, so they look live. Only cargo test reveals the truth.

References

  • Fastly Compute Rust SDK crate — note the target restriction in the documentation
  • Related skill: fastly-compute-rust-edition2024-fix — different failure mode (build-time dependency incompatibility) but shares the "Fastly Compute crate has unusual constraints around native tooling" theme

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Fix ArgoCD ExternalSecret deployment failing with "namespace X is not permitted in project Y". Use when: (1) ExternalSecret shows OutOfSync in ArgoCD but won't sync, (2) ArgoCD application status shows "namespace X is not permitted in project 'infrastructure'", (3) ExternalSecret targets a namespace managed by a different ArgoCD project, (4) Using apps-of-apps pattern with separate infrastructure and application projects.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

divinevideo/divine-mobile2662026년 10월 19일 업데이트

Art direction for any content — reads text, PDF, Word, HTML, PPT, then proposes 2-3 creative directions with photography style, mood, and visual language. After selection, generates AI image prompts and visual briefs section-by-section. Use when the user shares content and needs visual direction, image sourcing, or creative direction for any material.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

divinevideo/divine-mobile2662026년 10월 19일 업데이트

Fix "Null check operator used on a null value" errors when an object is set to null during an async await. Use when: (1) Object reference is nullified while awaiting, (2) Code accesses object with ! after await returns, (3) Cancel/dispose operations run concurrently with async operations on same object. Solution: capture local reference before await.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

divinevideo/divine-mobile2662026년 10월 19일 업데이트

Add custom metadata headers (x-amz-meta-*) to AWS v4 signed requests for GCS S3-compatible API. Use when: (1) Adding custom metadata to GCS uploads via S3 API, (2) Getting signature mismatch errors after adding new headers, (3) x-amz-meta-* headers being ignored or causing 403 errors. Custom headers MUST be included in canonical headers and signed headers list.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

divinevideo/divine-mobile2662026년 10월 19일 업데이트

Fix password/secret authentication failures caused by trailing newlines when creating Google Cloud secrets (or similar) with bash here-strings. Use when: (1) Password authentication fails with correct password, (2) Secret created with `<<< "value"` syntax, (3) Error like "password authentication failed" or "invalid token" despite correct value. Bash here-strings (`<<<`) add a trailing newline that corrupts secrets.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

divinevideo/divine-mobile2662026년 10월 19일 업데이트

Fix silent video/media processing failures caused by URL extraction code that filters on file extensions (.mp4, .webm, .webp). Use when: (1) Media moderation, transcoding, or analysis silently skips files from Blossom or content-addressed storage servers, (2) URL extraction from Nostr event tags (imeta, r tags) drops URLs without recognized extensions, (3) CDN fallback URLs append .mp4 but the actual server uses extensionless content-addressed paths like /{sha256}. Common in Nostr video events (kind 34236) where different clients use different URL formats.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

divinevideo/divine-mobile2662026년 10월 19일 업데이트

divinevideo의 스킬 모두 보기

이 스킬의 문제 신고