{"record":{"id":"e103fc29c836687e","repo":"Yeachan-Heo/oh-my-codex","slug":"name-is-required","errorCode":null,"errorMessage":"${name} is required","messagePattern":"(.+?) is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/mcp/hermes-bridge.ts","lineNumber":136,"sourceCode":"const DEFAULT_TAIL_LINES = 80;\nconst MAX_TAIL_LINES = 500;\nconst MAX_TAIL_READ_BYTES = 256_000;\nconst OMX_INSTANCE_OPTION = \"@omx_instance_id\";\n\nfunction jsonResult<T extends Record<string, unknown>>(data: T): HermesBridgeResult<T> {\n  return { ok: true, data };\n}\n\nfunction failure<T extends Record<string, unknown> = Record<string, unknown>>(\n  code: HermesBridgeFailureCode,\n  error: string,\n): HermesBridgeResult<T> {\n  return { ok: false, code, error };\n}\n\nfunction normalizeString(value: unknown, name: string, options: { required?: boolean } = {}): string | undefined {\n  if (value == null) {\n    if (options.required) throw new Error(`${name} is required`);\n    return undefined;\n  }\n  if (typeof value !== \"string\") throw new Error(`${name} must be a string`);\n  const trimmed = value.trim();\n  if (!trimmed && options.required) throw new Error(`${name} must be non-empty`);\n  return trimmed || undefined;\n}\n\nfunction requireMutation(args: Record<string, unknown>): void {\n  if (args.allow_mutation !== true) {\n    throw new Error(\"mutating Hermes bridge tools require allow_mutation: true\");\n  }\n}\n\nfunction normalizePositiveInteger(value: unknown, fallback: number, max: number): number {\n  if (value == null) return fallback;\n  const parsed = typeof value === \"number\" ? value : Number.parseInt(String(value), 10);\n  if (!Number.isInteger(parsed) || parsed <= 0) return fallback;","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/mcp/hermes-bridge.ts#L118-L154","documentation":"normalizeString is the shared input validator for Hermes bridge MCP tool arguments; it throws 'X is required' when a required argument (cwd, sessionId, status, questionId, prompt, actor) is null/undefined. MCP tool calls arrive as loosely typed JSON, so missing keys are common client mistakes.","triggerScenarios":"Calling a Hermes bridge tool without a required key, e.g. hermesSendPrompt({args:{}}) where prompt is required, or passing explicit null for a required field.","commonSituations":"MCP client omitting a field, wrong tool parameter name (prompt vs input), or a schema/client version mismatch where a field was renamed.","solutions":["Include the required field named in the error message with a non-null value","Check the tool's input schema for required parameter names","Upgrade client and server to matching versions if a field was renamed"],"exampleFix":"// before\nhermesSendPrompt({ session_id: \"s1\" })\n// after\nhermesSendPrompt({ session_id: \"s1\", prompt: \"continue\" })","handlingStrategy":"type-guard","validationCode":"for (const k of ['session_id','prompt']) { if (args[k] == null) throw new Error(`${k} required`); }","typeGuard":"function hasRequired<T extends object, K extends string>(o: T, k: K): o is T & Record<K,string> { return o[k] != null; }","tryCatchPattern":"catch (e) { if ((e as Error).message.endsWith('is required')) { /* fill missing field and retry */ } }","preventionTips":["Build typed request objects before MCP calls","Validate against the tool schema client-side","Fail fast on undefined variables"],"tags":["mcp","hermes-bridge","argument-validation"],"backgroundTag":"missing-required-field","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}