{"record":{"id":"65767776834c1d2a","repo":"nikivdev/code","slug":"todo-title-cannot-be-empty","errorCode":null,"errorMessage":"todo title cannot be empty","messagePattern":"todo title cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/todo.rs","lineNumber":124,"sourceCode":"    let now = Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true);\n    let ul_id = format!(\"_{}\", Uuid::new_v4().simple());\n    let li_id = Uuid::new_v4().simple().to_string();\n    format!(\n        \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n<html>\\n  <head>\\n    <meta charset=\\\"utf-8\\\"/>\\n  </head>\\n  <body>\\n    <ul id=\\\"{}\\\" data-created=\\\"{}\\\" data-modified=\\\"{}\\\">\\n      <li id=\\\"{}\\\" data-created=\\\"{}\\\" data-modified=\\\"{}\\\">\\n        <p>{}</p>\\n      </li>\\n    </ul>\\n  </body>\\n</html>\\n\",\n        ul_id, now, now, li_id, now, now, project_name\n    )\n}\n\nfn add(\n    title: &str,\n    note: Option<&str>,\n    session: Option<&str>,\n    no_session: bool,\n    status: TodoStatusArg,\n) -> Result<()> {\n    let trimmed = title.trim();\n    if trimmed.is_empty() {\n        bail!(\"todo title cannot be empty\");\n    }\n    let (path, mut items) = load_items()?;\n    let session_ref = resolve_session_ref(session, no_session)?;\n    let now = Utc::now().to_rfc3339();\n    let item = TodoItem {\n        id: Uuid::new_v4().simple().to_string(),\n        title: trimmed.to_string(),\n        status: status_to_string(status).to_string(),\n        created_at: now,\n        updated_at: None,\n        note: note.map(|n| n.trim().to_string()).filter(|n| !n.is_empty()),\n        session: session_ref,\n        external_ref: None,\n        priority: None,\n    };\n    items.push(item.clone());\n    save_items(&path, &items)?;\n    println!(\"✓ Added {} [{}]\", item.id, item.title);","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/todo.rs#L106-L142","documentation":"Raised by the add function (src/todo.rs:124) when the todo title argument, after trimming whitespace, is an empty string. The library refuses to create a todo item without a title since the title is the item's only meaningful content.","triggerScenarios":"Calling `f todo add` (via run) with an empty string, a whitespace-only string like \"   \", or with the title argument missing/quoted empty in a shell script.","commonSituations":"Shell variable interpolation producing an empty value (`f todo add \"$UNSET_VAR\"`); accidentally passing only flags so the positional title is empty; copy-pasting a command with the title dropped.","solutions":["Provide a non-empty title: `f todo add \"buy groceries\"`.","Check that shell variables used in the title are actually set (use \"${VAR:?unset}\" to fail fast).","Quote the title to prevent the shell from splitting/dropping it."],"exampleFix":"// before\nf todo add \"$TITLE\"\n// after: guard against empty/unset variable in shell\nf todo add \"${TITLE:?TITLE must be non-empty}\"","handlingStrategy":"validation","validationCode":"const title = process.argv[3] ?? \"\";\nif (title.trim().length === 0) {\n  throw new Error(\"todo title must be a non-empty string\");\n}\n// safe to call: f todo add \"<title>\"","typeGuard":"function isNonEmptyTitle(t: unknown): t is string {\n  return typeof t === \"string\" && t.trim().length > 0;\n}","tryCatchPattern":"try {\n  addTodo(title);\n} catch (e) {\n  if (String(e).includes(\"todo title cannot be empty\")) {\n    console.error(\"Pass a quoted, non-empty title\");\n  } else throw e;\n}","preventionTips":["Always quote the title argument in shell commands.","Use ${VAR:?msg} to fail fast on unset variables used as titles.","Trim and validate user-supplied titles before passing them to the CLI."],"tags":["validation","cli","empty-input"],"backgroundTag":"empty-required-argument","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}