Wei-Shaw/sub2api · error

ChatGPT DeviceCheck token generation timed out

Error message

ChatGPT DeviceCheck token generation timed out

What it means

The darwin provider shells out to the ChatGPT app's bundled Node runtime to produce a DeviceCheck token, with a context deadline (attestationTimeout) enforced via command.Run under runCtx. If the child process is killed by the deadline (runCtx.Err() is DeadlineExceeded), this specific timeout error is returned instead of a generic exec failure.

Source

Thrown at backend/internal/platform/liveattestation/attestation_darwin.go:123

	signalsJSON, err := json.Marshal(signals)
	if err != nil {
		return "", fmt.Errorf("encode Live attestation signals: %w", err)
	}

	command := exec.CommandContext(runCtx, nodePath, "-e", deviceCheckScript)
	command.Env = []string{
		"PATH=/usr/bin:/bin",
		"SUB2API_DEVICECHECK_MODULE=" + modulePath,
		"SUB2API_ATTESTATION_BUNDLE_ID=" + bundleID,
		"SUB2API_ATTESTATION_SIGNALS=" + string(signalsJSON),
	}
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	command.Stdout = &stdout
	command.Stderr = &stderr
	if err := command.Run(); err != nil {
		if errors.Is(runCtx.Err(), context.DeadlineExceeded) {
			return "", errors.New("ChatGPT DeviceCheck token generation timed out")
		}
		reason := strings.TrimSpace(stderr.String())
		if len(reason) > 240 {
			reason = reason[:240]
		}
		if reason == "" {
			reason = err.Error()
		}
		return "", fmt.Errorf("ChatGPT DeviceCheck token generation failed: %s", reason)
	}
	header := strings.TrimSpace(stdout.String())
	if len(header) < 20 || len(header) > 16*1024 || !json.Valid([]byte(header)) {
		return "", errors.New("ChatGPT DeviceCheck returned a malformed attestation")
	}
	return header, nil
}

func (p *darwinProvider) findApplication() (string, error) {

View on GitHub (pinned to 073e92d171)

Solutions

  1. Launch the ChatGPT app once interactively to clear Gatekeeper and Keychain prompts, then retry.
  2. Check system load / memory pressure on the macOS host.
  3. Retry the request; transient subprocess hangs usually clear after the first successful run warms caches.
  4. If timeouts persist, profile the node invocation manually with the documented SUB2API_* env vars to see where it stalls.
Defensive patterns

Strategy: retry

Try / catch

tok, err := provider.Generate(ctx)
if err != nil && strings.Contains(err.Error(), "timed out") {
    tok, err = provider.Generate(ctx) // first-run Gatekeeper/Keychain warmup is common
}

Prevention

When it happens

Trigger: The node subprocess hangs: first-run Gatekeeper prompts, disk pressure, the native module blocking on Keychain access, or system under heavy load such that token generation exceeds attestationTimeout.

Common situations: macOS Gatekeeper/first-launch verification of the ChatGPT app binaries; Keychain access prompts waiting for user consent; overloaded or memory-throttled servers; slept/latency-spiking disks.

Understand the failure class

Related errors


AI-assisted analysis of Wei-Shaw/sub2api@073e92d171 (2026-08-15). Data as JSON: /api/errors/2f199be1ede4a4b0. Report an issue: GitHub.