-
What version of Remix are you using?1.16.1 Are all your remix dependencies & dev-dependencies using the same version?
Steps to ReproduceIf you have a multipart/form-data form with both file and text inputs, it appears you can only capture either the text or file inputs, bot not both. Example form: Action function: Expected BehaviorTo be able to access both file and text values sent from form. Actual BehaviorAttempting to access text values from await formData() results in an error: Text values from unstable_parseMultipartFormData are always null |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
|
Remix has split up form data parsing into a pipeline. export const action = async ({ request }: ActionArgs) => {
const uploadHandler = unstable_composeUploadHandlers(
// handle file uploads
unstable_createFileUploadHandler({
directory: './public/uploads',
file: ({ filename }) => filename
}),
// fallback to memory for everything else
unstable_createMemoryUploadHandler()
);
const formData = await unstable_parseMultipartFormData(
request,
uploadHandler
);
const upload = formData.get("upload") as File;
const bio = formData.get("title");
// ...
};https://remix.run/docs/en/1.17.0/guides/file-uploads#upload-handler-composition |
Beta Was this translation helpful? Give feedback.
-
|
The accepted answer is the right fix for the parsing pipeline: compose the upload handlers so you can read both the file field and the text fields. After that, I’d still avoid treating the upload as trusted just because parsing succeeded. A safer flow is: parse multipart -> inspect file -> then store/promote That’s exactly where Pompelmi fits well. Example: import {
unstable_composeUploadHandlers,
unstable_createMemoryUploadHandler,
unstable_parseMultipartFormData,
json,
} from '@remix-run/node'
import type { ActionArgs } from '@remix-run/node'
import { scanBytes, STRICT_PUBLIC_UPLOAD } from 'pompelmi'
export async function action({ request }: ActionArgs) {
const uploadHandler = unstable_composeUploadHandlers(
unstable_createMemoryUploadHandler()
)
const formData = await unstable_parseMultipartFormData(request, uploadHandler)
const title = formData.get('title')
const file = formData.get('upload')
if (!(file instanceof File)) {
return json({ error: 'Missing file' }, { status: 400 })
}
const report = await scanBytes(Buffer.from(await file.arrayBuffer()), {
filename: file.name,
mimeType: file.type || 'application/octet-stream',
policy: STRICT_PUBLIC_UPLOAD,
failClosed: true,
})
if (report.verdict !== 'clean') {
return json({ error: `Rejected upload: ${report.verdict}` }, { status: 400 })
}
// persist only after inspection
return json({
ok: true,
title,
verdict: report.verdict,
})
} |
Beta Was this translation helpful? Give feedback.
Remix has split up form data parsing into a pipeline.
unstable_createFileUploadHandler()only handlesfiledata. You still need to useunstable_createMemoryUploadHandler()to get the rest. You combine upload handlers viaunstable_composeUploadHandlers()