sipeed/picoclaw · error

failed to create request: %w

Error message

failed to create request: %w

What it means

Returned by WhisperTranscriber.doRequest when http.NewRequestWithContext rejects the POST URL built by transcriptionURL() (apiBase + '/audio/transcriptions'). NewRequestWithContext fails on a malformed URL: missing scheme, whitespace or control characters, or invalid percent-encoding in the configured api_base. The method (POST) and body are always valid.

Source

Thrown at pkg/audio/asr/whisper_transcriber.go:188

	if err = writer.Close(); err != nil {
		return nil, fmt.Errorf("failed to close multipart writer: %w", err)
	}

	return t.doRequest(ctx, &requestBody, writer.FormDataContentType(), fileInfo.Size())
}

func (t *WhisperTranscriber) doRequest(
	ctx context.Context,
	requestBody *bytes.Buffer,
	contentType string,
	fileSize int64,
) (*TranscriptionResponse, error) {
	url := t.transcriptionURL()
	req, err := http.NewRequestWithContext(ctx, "POST", url, requestBody)
	if err != nil {
		logger.ErrorCF("voice", "Failed to create whisper request", map[string]any{"error": err})
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	req.Header.Set("Content-Type", contentType)
	if t.apiKey != "" {
		req.Header.Set("Authorization", "Bearer "+t.apiKey)
	}

	logger.DebugCF("voice", "Sending whisper transcription request", map[string]any{
		"file_size_bytes":    fileSize,
		"model":              t.modelID,
		"provider":           t.providerName,
		"request_size_bytes": requestBody.Len(),
		"url":                url,
	})

	resp, err := t.httpClient.Do(req)
	if err != nil {
		logger.ErrorCF("voice", "Failed to send whisper request", map[string]any{"error": err})

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Set api_base to a full URL including scheme, e.g. https://api.groq.com/openai/v1
  2. Trim whitespace from the api_base config value
  3. url.Parse the base at startup and fail configuration early
  4. Log transcriptionURL() output to see the exact string being rejected

Example fix

// before
apiBase := `api.groq.com/openai/v1` // missing scheme -> request creation fails
// after
apiBase := `https://api.groq.com/openai/v1`
if _, err := url.Parse(apiBase); err != nil {
    return fmt.Errorf(`invalid api_base: %w`, err)
}
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(strings.TrimSpace(cfg.APIBase))
if err != nil || u.Scheme == `` || u.Host == `` {
    return fmt.Errorf(`invalid api_base %q: include scheme and host`, cfg.APIBase)
}

Type guard

func isInvalidURL(err error) bool {
    return err != nil && (strings.Contains(err.Error(), `invalid URI`) ||
        strings.Contains(err.Error(), `missing protocol scheme`) ||
        strings.Contains(err.Error(), `invalid control character`))
}

Try / catch

if err != nil {
    // non-retriable config error: fix api_base (add https://, strip whitespace) before retrying
}

Prevention

When it happens

Trigger: api_base configured as 'api.groq.com/openai/v1' without https://; trailing whitespace or newline in the config value; a custom endpoint path with characters that break url.Parse.

Common situations: Hand-edited config files; environment variables for the API base missing the scheme; copy-paste artifacts such as trailing spaces.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/554fbac2ba1c5a5f. Report an issue: GitHub.