{"record":{"id":"85889fa42e49f5cf","repo":"sipeed/picoclaw","slug":"failed-to-create-form-file-w-85889f","errorCode":null,"errorMessage":"failed to create form file: %w","messagePattern":"failed to create form file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/audio/asr/whisper_transcriber.go","lineNumber":107,"sourceCode":"func (t *WhisperTranscriber) TranscribeData(\n\tctx context.Context,\n\tdata []byte,\n\tfilename string,\n) (*TranscriptionResponse, error) {\n\tlogger.InfoCF(\"voice\", \"Starting whisper transcription from memory\", map[string]any{\n\t\t\"bytes\":    len(data),\n\t\t\"filename\": filename,\n\t\t\"model\":    t.modelID,\n\t\t\"provider\": t.providerName,\n\t})\n\n\tvar requestBody bytes.Buffer\n\twriter := multipart.NewWriter(&requestBody)\n\n\tpart, err := writer.CreateFormFile(\"file\", filename)\n\tif err != nil {\n\t\tlogger.ErrorCF(\"voice\", \"Failed to create whisper form file\", map[string]any{\"error\": err})\n\t\treturn nil, fmt.Errorf(\"failed to create form file: %w\", err)\n\t}\n\n\tif _, copyErr := io.Copy(part, bytes.NewReader(data)); copyErr != nil {\n\t\tlogger.ErrorCF(\"voice\", \"Failed to copy whisper file content\", map[string]any{\"error\": copyErr})\n\t\treturn nil, fmt.Errorf(\"failed to copy file content: %w\", copyErr)\n\t}\n\n\tif err = writer.WriteField(\"model\", t.modelID); err != nil {\n\t\tlogger.ErrorCF(\"voice\", \"Failed to write whisper model field\", map[string]any{\"error\": err})\n\t\treturn nil, fmt.Errorf(\"failed to write model field: %w\", err)\n\t}\n\n\tif err = writer.WriteField(\"response_format\", \"json\"); err != nil {\n\t\tlogger.ErrorCF(\"voice\", \"Failed to write whisper response_format field\", map[string]any{\"error\": err})\n\t\treturn nil, fmt.Errorf(\"failed to write response_format field: %w\", err)\n\t}\n\n\tif err = writer.Close(); err != nil {","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/audio/asr/whisper_transcriber.go#L89-L125","documentation":"Thrown when multipart.Writer.CreateFormFile(\"file\", filename) fails in WhisperTranscriber's bytes-based path (transcribing in-memory data). Identical semantics to the ElevenLabs case: the filename cannot be encoded into the Content-Disposition header (control characters, CR/LF, non-UTF-8 bytes) or the destination bytes.Buffer cannot allocate. The data itself is already in memory, so file I/O is not involved.","triggerScenarios":"Caller-supplied filename (used for both the form field and format detection elsewhere) contains \\r, \\n, quotes, or invalid UTF-8; memory exhaustion while buffering large audio.","commonSituations":"Filename built by string concatenation that accidentally embeds user text or a newline; blobs transcoded with machine-generated names containing odd bytes.","solutions":["Sanitize the filename: keep [A-Za-z0-9._-] plus a known extension.","Log the filename with %q to reveal invisible characters.","If filenames are clean, treat as memory pressure (see buffer errors)."],"exampleFix":"// before\npart, err := writer.CreateFormFile(\"file\", filename)\n\n// after\nvar b strings.Builder\nfor _, r := range filename {\n    if r >= 32 && r < 127 && r != '\"' { b.WriteRune(r) }\n}\nsafe := b.String()\nif safe == \"\" { safe = \"audio.wav\" }\npart, err := writer.CreateFormFile(\"file\", safe)","handlingStrategy":"validation","validationCode":"func validUploadName(name string) error {\n    if !utf8.ValidString(name) || strings.ContainsAny(name, \"\\\"\\r\\n\\\\;\") {\n        return fmt.Errorf(\"rejecting unsafe upload filename %q\", name)\n    }\n    return nil\n}","typeGuard":"func hasUnsafeMimeChars(s string) bool {\n    return strings.IndexFunc(s, func(r rune) bool { return r < 32 || r == 127 || r == '\"' || r == '\\\\' }) >= 0\n}","tryCatchPattern":"if err := validUploadName(filename); err != nil { return err }\nif _, err := whisper.TranscribeWithData(ctx, data, filename); err != nil {\n    if strings.Contains(err.Error(), \"failed to create form file\") {\n        return fmt.Errorf(\"filename %q rejected; rename and retry\", filename)\n    }\n    return err\n}","preventionTips":["Derive filenames from trusted constants plus a timestamp; never splice user text into them.","Validate filenames at the API boundary, not inside the HTTP client."],"tags":["multipart","filename","whisper","audio","go"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}