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

  1. Sanitize entries: a.replace(/\x00/g, "") or reject at the client with a clear message
  2. Verify the source of the args is text (decode as UTF-8 and validate) before building the payload
  3. 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

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


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/21637055f7440c20. Report an issue: GitHub.