davila7/claude-code-templates · error · Error

Invalid response from x0.at: ${uploadUrl || stderr}

Error message

Invalid response from x0.at: ${uploadUrl || stderr}

What it means

Thrown by uploadToX0() in cli-tool/src/session-sharing.js when the x0.at file-hosting service returns a response that is empty or does not start with 'http'. The tool uploads a session archive with curl and expects the plain-text share URL on stdout; anything else (an HTML error page, a rate-limit message, an empty body) fails this check. The error message includes whatever was received (or stderr) to help diagnose the service response.

Source

Thrown at cli-tool/src/session-sharing.js:241

      await fs.writeFile(tmpFile, JSON.stringify(sessionData, null, 2), 'utf8');

      console.log(chalk.gray(`📁 Created temp file: ${tmpFile}`));
      console.log(chalk.gray(`📤 Uploading to x0.at...`));

      // Upload to x0.at using curl with form data
      // x0.at API: curl -F'file=@yourfile.png' https://x0.at
      // Response: Direct URL in plain text
      const { stdout, stderr } = await execAsync(
        `curl -s -F "file=@${tmpFile}" ${this.uploadUrl}`,
        { maxBuffer: 10 * 1024 * 1024 } // 10MB buffer
      );

      // x0.at returns URL directly in plain text
      const uploadUrl = stdout.trim();

      // Validate response
      if (!uploadUrl || !uploadUrl.startsWith('http')) {
        throw new Error(`Invalid response from x0.at: ${uploadUrl || stderr}`);
      }

      console.log(chalk.green(`✅ Uploaded to x0.at successfully`));
      console.log(chalk.yellow(`⚠️  Files kept for 3-100 days (based on size)`));
      console.log(chalk.gray(`🔓 Note: Files are not encrypted by default`));

      // Clean up temp file
      await fs.remove(tmpFile);

      return uploadUrl;
    } catch (error) {
      // Clean up temp file on error
      await fs.remove(tmpFile).catch(() => {});
      throw error;
    }
  }

  /**

View on GitHub (pinned to a0851ed10c)

Solutions

  1. Check the message payload: if it contains HTML or an error status, x0.at rejected the upload — shrink the session file or retry later
  2. Verify curl is installed and reachable: curl -I https://x0.at
  3. Retry after a short delay — x0.at rate-limits or has transient outages
  4. If the session is large, prune old messages from the session before sharing

Example fix

// before
if (!uploadUrl || !uploadUrl.startsWith('http')) {
  throw new Error(`Invalid response from x0.at: ${uploadUrl || stderr}`);
}

// after
if (!uploadUrl || !uploadUrl.startsWith('http')) {
  throw new Error(`Invalid response from x0.at: ${uploadUrl || stderr || 'empty response (service may be down or file too large)'}`);
}
Defensive patterns

Strategy: retry

Validate before calling

const https = require('https');
https.get('https://x0.at', res => console.log('x0.at reachable:', res.statusCode));

Try / catch

try {
  const url = await sharer.uploadToX0(file);
} catch (e) {
  if (/Invalid response from x0\.at/.test(e.message)) {
    await sleep(5000);
    return retry(attempts - 1); // transient service errors are common
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling shareSession()/uploadToX0() when x0.at is down, rate-limiting, returns an HTML error page (e.g. '413 Request Entity Too Large'), or when curl fails silently and stdout is empty. Also triggered if the session archive exceeds x0.at's size limit.

Common situations: Sharing a very large session file that exceeds x0.at's upload cap; x0.at temporarily offline or behind a maintenance page; corporate proxies stripping the response body; curl not installed so stdout is empty.

Related errors


AI-assisted analysis of davila7/claude-code-templates@a0851ed10c (2026-08-28). Data as JSON: /api/errors/66eec2d632c821ce. Report an issue: GitHub.