{"record":{"id":"903d5409ce29c2cf","repo":"nanocoai/nanoclaw","slug":"msg-usage","errorCode":null,"errorMessage":"${msg}\n\n${usage}","messagePattern":"\\$\\{msg\\}\n\n\\$\\{usage\\}","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/crud.ts","lineNumber":544,"sourceCode":"  // can fix the invocation without a second help round-trip.\n  if (def.customOperations) {\n    for (const [verb, op] of Object.entries(def.customOperations)) {\n      const declared = op.args;\n      register({\n        name: `${def.plural}-${verb.replace(/ /g, '-')}`,\n        action: `${def.plural}.${verb.replace(/ /g, '.')}`,\n        description: op.description,\n        access: op.access,\n        hostOnly: op.hostOnly,\n        resource: def.plural,\n        parseArgs: declared\n          ? (raw) => {\n              try {\n                return validateArgs(declared, normalizeArgs(raw));\n              } catch (e) {\n                const usage = renderVerbHelp(def, verb);\n                const msg = e instanceof Error ? e.message : String(e);\n                throw new Error(usage ? `${msg}\\n\\n${usage}` : msg, { cause: e });\n              }\n            }\n          : (raw) => normalizeArgs(raw),\n        handler: async (args, ctx) => op.handler(args as Record<string, unknown>, ctx),\n        formatHuman: op.formatHuman,\n      });\n    }\n  }\n}\n","sourceCodeStart":526,"sourceCodeEnd":554,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/cli/crud.ts#L526-L554","documentation":"This is not a distinct failure but the wrapper around strict validation for custom verbs: any validateArgs failure (unknown flag, required, type, JSON, enum) is re-thrown with the verb's rendered usage block appended, separated by a blank line, and the original error preserved as `cause`. It exists so a human or agent caller can fix the invocation in one round-trip instead of issuing a separate help command.","triggerScenarios":"Any of errors 32–38 occurring on a custom operation (a verb defined in `customOperations` with declared `args`). E.g. `ncl groups restart --id g1 --mesage x` produces \"unknown flag --mesage\" plus the restart usage text.","commonSituations":"Parsers that split the error on newlines and only surface the first line lose the usage context; agents that retry blindly instead of reading the appended usage; tests asserting exact error strings breaking when usage is appended.","solutions":["Read the full message — the usage block after the blank line lists accepted flags and required markers","Fix the underlying validation issue named on the first line","Programmatically, inspect `error.cause` for the original un-wrapped validation error","For tests, assert with `.startsWith()` or match on the first line only"],"exampleFix":"// before (test asserts exact message)\nexpect(() => parse(args)).toThrow('unknown flag --rebild');\n\n// after\nexpect(() => parse(args)).toThrow(/^unknown flag --rebild/);","handlingStrategy":"try-catch","validationCode":"null","typeGuard":null,"tryCatchPattern":"catch (e) {\n  if (e instanceof Error) {\n    const [first, usage] = e.message.split('\\n\\n');\n    // first line = underlying validation error; usage = rendered help\n    const root = e.cause; // original validateArgs error\n  }\n}","preventionTips":["Parse the message on the first line; render the usage block to the user","In tests, match messages with startsWith/regex, not exact equality","Use error.cause to get the unwrapped validation error programmatically"],"tags":["cli","usage","error-wrapping","argument-validation"],"backgroundTag":"usage-help-in-errors","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}