anomalyco/sst · error
failed to initialize assets upload: no JWT received
Error message
failed to initialize assets upload: no JWT received
What it means
Cloudflare returned HTTP 200 for the assets-upload-session request, but the decoded result.jwt field was empty. The JWT is the session token required to authorize subsequent asset uploads, so the library refuses to continue without it. This typically indicates an unexpected API response shape or an API-side anomaly.
Source
Thrown at pkg/server/resource/cloudflare-worker-assets.go:208
}
defer resp.Body.Close()
// print out response body as a string
if resp.StatusCode != http.StatusOK {
responseBody, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("failed to initialize assets upload: HTTP %d %s", resp.StatusCode, string(responseBody))
}
var result struct {
Result InitializeAssetsResponse `json:"result"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
if result.Result.Jwt == "" {
return nil, fmt.Errorf("failed to initialize assets upload: no JWT received")
}
return &result.Result, nil
}
func (r *WorkerAssets) uploadAssets(manifest AssetManifest, directory, accountId, apiToken string, hashes []string, jwt string) (string, error) {
var body bytes.Buffer
writer := multipart.NewWriter(&body)
for _, hash := range hashes {
// Find the file path for this hash in the manifest
var fileKey string
var contentType string
for path, entry := range manifest {
if entry.Hash == hash {
fileKey = path
contentType = entry.ContentType
breakView on GitHub (pinned to a0bd20f762)
Solutions
- Log the raw response body when jwt is empty to see what Cloudflare actually returned.
- Retry the deploy — transient API-side session failures often clear.
- Check Cloudflare's API changelog/status for changes to the assets-upload-session response schema.
- Ensure no proxy or corporate gateway is rewriting the response (decode errors or empty bodies from HTML pages).
- Report/upgrade if the platform's response parsing is out of date with the current Cloudflare API.
Defensive patterns
Strategy: retry
Validate before calling
// after a session call, assert the envelope before trusting it
if (!data.success || !data.result || typeof data.result.jwt !== "string" || !data.result.jwt) {
throw new Error(`unexpected session response: ${JSON.stringify(data).slice(0, 500)}`);
} Type guard
function hasJwt(r: unknown): r is { result: { jwt: string; buckets: string[][] } } {
const o = r as any;
return !!o && typeof o === "object" &&
typeof o.result?.jwt === "string" && o.result.jwt.length > 0 &&
Array.isArray(o.result?.buckets);
} Try / catch
try {
session = await initAssetSession(manifest);
} catch (e) {
if (String(e).includes("no JWT received")) {
console.error("Cloudflare returned 200 without a session JWT - check raw response/API version");
session = await retryWithBackoff(() => initAssetSession(manifest), { attempts: 3 });
} else throw e;
} Prevention
- Log the raw HTTP body on any empty-jwt response
- Retry session creation on empty JWT (transient API behavior)
- Watch Cloudflare API changelog for response schema changes
- Bypass/inspect corporate proxies that can rewrite API responses
When it happens
Trigger: Cloudflare responds 200 but with a JSON body whose result.jwt is missing or empty — e.g. an API schema change, an error payload wrapped in a 200, or a response where result.success is false but the HTTP status is still 200.
Common situations: Cloudflare API version drift changing the response envelope; the token being valid but the session creation silently failing server-side; proxy/gateway injecting a 200 HTML or partial JSON page that decodes into a zero-value struct.
Related errors
- failed to complete asset upload - no completion JWT received
- failed to initialize assets upload: HTTP %d %s
- failed to upload assets: HTTP %d %s
- SSR server bundle not found in the build output at: "${pat
- You cannot provide both "job" and "worker" in the "${name}"
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/d4807e88e31d4626.
Report an issue: GitHub.