slopus/happy · error · Error

request-upload returned an invalid response

Error message

request-upload returned an invalid response

What it means

Thrown by requestAttachmentUpload when the server's response to the request-upload call fails structural validation: upload is missing, ref/uploadUrl are not strings, or method is present but not PUT or POST. The client treats this as a contract violation of the upload API rather than a transport error.

Source

Thrown at packages/happy-cli/src/api/apiSession.ts:429

    private async requestAttachmentUpload(filename: string, size: number): Promise<AttachmentUploadResult> {
        const response = await axios.post<AttachmentUploadResult>(
            `${configuration.serverUrl}/v1/sessions/${encodeURIComponent(this.sessionId)}/attachments/request-upload`,
            { filename, size },
            {
                headers: this.authHeaders(),
                timeout: 30000,
            },
        );

        const upload = response.data;
        if (
            !upload
            || typeof upload.ref !== 'string'
            || typeof upload.uploadUrl !== 'string'
            || (upload.method !== undefined && upload.method !== 'PUT' && upload.method !== 'POST')
        ) {
            throw new Error('request-upload returned an invalid response');
        }

        return {
            ...upload,
            method: upload.method ?? 'PUT',
        };
    }

    private async uploadEncryptedAttachmentBlob(upload: AttachmentUploadResult, encrypted: Uint8Array): Promise<void> {
        if (upload.method === 'POST') {
            const { body, boundary } = buildMultipartUploadBody(upload.formFields, encrypted);
            await axios.post(upload.uploadUrl, body, {
                headers: {
                    'Content-Type': `multipart/form-data; boundary=${boundary}`,
                },
                timeout: 60000,
                maxBodyLength: 10 * 1024 * 1024,
            });

View on GitHub (pinned to b824cd0a46)

Solutions

  1. Check server logs and the raw response for the real cause (auth failure, 4xx/5xx body)
  2. Verify CLI and server versions are compatible — update the CLI or server
  3. Confirm the attachment upload endpoint is enabled/reachable and retry
Defensive patterns

Strategy: validation

Validate before calling

const res = await requestUpload(attachmentId);
const ok = res?.data?.ref && typeof res.data.uploadUrl === 'string'
  && ['PUT', 'POST', undefined].includes(res.data.method);
if (!ok) throw new Error('unexpected request-upload response');

Type guard

function isValidUploadResponse(u: any): u is { ref: string; uploadUrl: string; method?: 'PUT' | 'POST' } {
  return !!u && typeof u.ref === 'string' && typeof u.uploadUrl === 'string'
    && (u.method === undefined || u.method === 'PUT' || u.method === 'POST');
}

Try / catch

try {
  await upload(attachmentPath);
} catch (e) {
  if (e.message.includes('invalid response')) {
    // log raw server response; likely version skew or auth issue
  } throw e;
}

Prevention

When it happens

Trigger: Server returns an error body, empty data, or a malformed payload for request-upload; an API version skew changes the response shape (renamed fields, missing uploadUrl, unsupported method value).

Common situations: Pointing the CLI at an older/proxy server that doesn't implement request-upload; authenticated but unauthorized requests returning error JSON; server bug or partial outage.

Related errors


AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31). Data as JSON: /api/errors/60b09f90ed2a87f1. Report an issue: GitHub.