multica-ai/multica · error
fixed_args entries cannot contain NUL bytes
Error message
fixed_args entries cannot contain NUL bytes
What it means
marshalFixedArgs rejects fixed_args entries containing the NUL byte (\x00). Go strings can hold NUL, but OS exec argv is C-string terminated, so a NUL inside an argument would silently truncate the flag at exec time. The check exists to fail fast at the API boundary instead of corrupting the spawned command line.
Source
Thrown at server/internal/handler/runtime_profile.go:96
// visibility control only once those read paths enforce creator visibility.
// Follow-up: MUL-3308.
const runtimeProfileDefaultVisibility = "workspace"
// marshalFixedArgs validates and JSON-encodes the fixed_args list. Each entry
// must be a non-empty string; the column defaults to an empty array.
func marshalFixedArgs(args []string) ([]byte, error) {
if len(args) == 0 {
return []byte("[]"), nil
}
clean := make([]string, 0, len(args))
for _, a := range args {
// fixed_args are launch flags inherited by every agent on the runtime;
// blank entries are always a client mistake.
if strings.TrimSpace(a) == "" {
return nil, errors.New("fixed_args entries must be non-empty")
}
if strings.ContainsRune(a, '\x00') {
return nil, errors.New("fixed_args entries cannot contain NUL bytes")
}
clean = append(clean, a)
}
return json.Marshal(clean)
}
func validateRuntimeProfileCommandName(commandName string) error {
if commandName == "" {
return errors.New("command_name is required")
}
if strings.ContainsAny(commandName, " \t\r\n") {
return errors.New("command_name must be a single executable token; put arguments in fixed_args")
}
if strings.ContainsRune(commandName, '\x00') {
return errors.New("command_name cannot contain NUL bytes")
}
return nil
}View on GitHub (pinned to 2c0912b6ec)
Solutions
- Sanitize entries: a.replace(/\x00/g, "") or reject at the client with a clear message
- Verify the source of the args is text (decode as UTF-8 and validate) before building the payload
- If you actually need to pass a NUL-containing value, that is impossible via argv — redesign to pass a file path or env var
Example fix
// before
fixedArgs: buffer.toString("utf8").split("\n")
// after
fixedArgs: buffer.toString("utf8").split("\n").map(s => s.replace(/\x00/g, "")).filter(Boolean) Defensive patterns
Strategy: validation
Validate before calling
const hasNul = (s: string) => s.includes('\x00');
const safeArgs = fixedArgs.map(a => a.replace(/\x00/g, ''));
if (fixedArgs.some(hasNul)) log.warn('NUL bytes stripped from fixed_args'); Type guard
function isNulFree(s: string): boolean { return !s.includes('\x00'); } Prevention
- Treat NUL in argv-destined strings as producer corruption — investigate the source
- Validate config text is valid UTF-8 without NUL at ingestion
- NUL cannot be passed through argv at all; redesign around files or env vars
When it happens
Trigger: POST/PUT a runtime profile whose fixed_args contains a literal \u0000 — usually binary data, a protocol frame, or a string built from a buffer that was not validated as UTF-8 text.
Common situations: Reading args from a binary config or message queue into strings; fuzzing tools injecting NUL; encoding mishaps where UCS-4/UTF-32 text is decoded per-byte leaving NULs between characters.
Related errors
- command_name cannot contain NUL bytes
- fixed_args entries must be non-empty
- command_name is required
- command_name must be a single executable token; put argument
- empty expected checksum for %q
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/21637055f7440c20.
Report an issue: GitHub.