A type error saved me from shipping a bug in my auth flow, all thanks to @DrizzleORM
In my application, some users can sign in with Google OAuth, so passwordHash is nullable in my user schema: passwordHash: text('password_hash')
In the standard email/password login route, I fetched the user and did: await compare(password, user.passwordHash)
Instantly, TypeScript complained that user.passwordHash could be null.
Without this type safety, If a Google OAuth user tried to use the standard login form, user.passwordHash would be null and crash the server.
Because Drizzle carried the database nullability straight into the query type, I was forced to handle this edge case before saving.
What surprised me is that I hadn't written any interfaces or types myself. Drizzle picked up the nullable field from the schema, and TypeScript carried that information all the way through the query.
A real bug without generating any types. Making it my first real wow moment.
@DrizzleORM schema doesn't just define your database. It also helps you reason about the application.
"it's just a quick schema change" starter pack:
- a column rename nobody told downstream about
- one nullable that should never have been nullable
- a friday deploy
- a monday incident channel
7/7
The pattern: discriminator column.
One table.
One type column.
Nullable context fields per type.
Works for: assessments, notifications,
content types, media, events.
When multiple similar things share most of their structure
โ ask if they belong in one table first.
4/7
The nullable fields:
lessonId โ only filled for QUIZ, null for others
moduleId โ only filled for EXAM, null for others
batchId โonly filled for SURPRISE,null for others
sessionIdโonly filled for MINITEST HOMEWORK
dueDateโonly filled for HOMEWORK
Database allows nulls.
2/7
Then I listed what each type actually needs:
All 6 have:
title, questions, attempts, status,
duration, shuffle options, results, passing score.
The difference?
A few nullable context fields and a type column.
Same shape. Different context.
๐Which C# version upgrade made the biggest difference in your daily work?
Was it:
โ LINQ
โ async/await
โ Records
โ Nullable Reference Types
โ Top-Level Statements
Or another feature?
Share your pick and why it changed the way you write .NET code. ๐
#csharp#niotechone
the pipeline ran green for six months. nobody touched it. nobody thanked it.
then someone added one nullable column and the whole thing remembered it was load-bearing duct tape the entire time.
๐๏ธ Weekly recap (Jun 6-Jun 13)
๐ 1 release
๐ ๏ธ 39 improvements
39 features & enhancements in this release
Top features:
โข Added /settings interactive dialog to browse and edit all user settings in one place
โข Added /worktree command (aliased /move) to create and switch to a new git worktree with uncommitted changes
โข /after and /every commands now appear in the /experimental slash command list with natural language scheduling support
โข Added full screen scrollbar for easier navigation
โข Added MCP OAuth re-authentication using saved OAuth client ID for remote servers
โข Added support for Claude Fable 5 and Gemini models with nullable schema types
โข /fork shows a "Creating fork..." progress notification while creating
โข /sessions now navigates to the Sessions tab instead of opening an overlay
โข Search bar match count stays inside the prompt frame for better UI clarity
โข Added beepOnSchedule setting to disable completion beeps for scheduled /every and /after runs
Enhancements:
โข Polished /agents picker and Create New Agent wizard with consistent borders, headers, and styled inputs โจ
โข Auto-load MCP servers from .github/mcp.json workspace config file
โข Press '/' in the /agent picker to filter agents by name
โข Number-key selection in pickers works for items 10 and beyond
โข GitHub theme adapts to light terminals with authentic GitHub Primer light color palette
โข Colors render correctly in WSL and tmux sessions, avoiding degraded palettes
โข Hook progress status lines marked as temporary collapse in place instead of accumulating
โข Grep and glob tools correctly handle single path arguments to prevent missed search results
โข Grep searches in large monorepos use an indexed search engine for significantly faster results ๐ฅ
โข Bash tool correctly handles multi-byte UTF-8 characters in command input
โข Added http/protobuf OTLP HTTP export via standard OpenTelemetry protocol environment variables
โข Prompt mode surfaces model-load errors on stderr instead of exiting silently
โข Configure home tab bar visibility, order, and hidden tabs via the tabs setting in settings.json
Bug fixes:
โข Fixed a bug where resuming a session could leave the screen blank
โข Resuming a local session with memory disabled no longer crashes the UI to a blank screen ๐ ๏ธ
โข Prevent crashes from malformed UTF-8, oversized string buffers, and terminal disconnect errors
โข GitHub issue and PR references inside existing links no longer create broken nested autolinks
โข Pasted images no longer leak into the main prompt after permission dialog closes
โข Symlinked directories now appear in file picker suggestions
โข MCP tools work correctly with Gemini models and nullable schema types
โข Fixed false positives in shell command validation that blocked harmless commands with words like "kill"
โข Light theme secondary background color now renders correctly
โข MCP search works correctly with external registries
โข Exit shell mode by pressing Esc or Ctrl C on empty prompt, in addition to Backspace
โข Fixed shell prompt color rendering issues in tmux and WSL
Misc:
โข Added /help listing $HOME/.copilot/instructions/**/*.instructions.md alongside other user-level instructions
โข Plugin install enforces managed marketplace policy even during network errors fetching settings
โข Added support for mTLS and private CA for OTLP telemetry export over HTTPS
โข Added /env output hides internal hooks and shows full file paths for hook sources
โข Added MCP servers auto-loading via workspace config
โข Added improved terminal UX polish for interactive dialogs and pickers
โข Improved tooling with indexed search engine for large repo greps
โข Hardened token and telemetry handling defaults
โข Improved stability and error handling in telemetry export
โข Added collapsible hook progress lines
โข Enhanced autocomplete UX with filtering and number-key selection
โข Updated internal docs and instructions for easier user customization
github.com/github/copilot-clโฆ#GitHubCopilotCLI
๐ฐ ๐ ๐๐๐๐๐๐ ๐๐๐๐๐ ๐๐๐-๐๐๐๐๐ ๐๐๐๐ ๐๐๐ ๐, ๐๐๐ ๐๐๐ ๐๐๐ ๐ ๐๐๐ ๐๐๐๐๐.
The starting point was the kind of anemic class AI loves to generate, unless you stop it. The result was 150 lines of code, with all primitive types, a state enum, nullable properties for every accompanying field, defensive validation all around, multi-way branches in every method, and an exception waiting at the end of each branch.
I rewrote it from scratch. The result has no nulls, no enums, and not a single throw (except in constructor validation). The compiler refuses to construct an invalid object, so there is nothing to catch at runtime.
And these are the usual objections:
- Good luck persisting that - EF Core, Dapper, document store, all support this style natively; those who object actually do not understand persistence well.
- Where did the validation go? - Into a handful of small types; once those exist, every composite that uses them is valid by construction.
- There's nothing wrong with the state enum - Oh, there is; enum never comes alone, and most of the accompanying variables will be nullable by force.
Bottom line, rampant validation is a symptom of weak types. The cure is a proper type system you design.
For full breakdown, refer to the new video: youtu.be/J4oWyIV3xA0
the four horsemen of the broken pipeline:
timezone, who arrives one hour off.
nullable, who promised it would never be empty.
encoding, who turned every name into a question mark.
and that one regex, who answers to no one.
Use interactive.type = voice_call and interactive.action.name = voice_call. Optional interactive.action.parameters:
โข display_text
โข ttl_minutes
โข payload
Also, GET /v1/whatsapp/calling now returns callDeepLink (nullable) for the public deep link when calling is enabled.
You know, C# is a typed language. The behavior of any of those lines depends on the types of those variables, fields, and methods.
That = there? That could be adding an event handler to an event!
Yes, if tickTimer is an event delegate, and Time.deltaTime is an appropriate handler, that will work just fine, but quite different to what you probably intended.
Same as OnTickEvent - that's possibly a method call! It could be a method that gracefully handles the nullable invocation!
We don't know because you didn't include any types! For all we know OnTickEvent could just call Environment.FailFast() and crash would have been the correct answer.
And that's all assuming that this is C# - you didn't even specify the language!
Kotlin helps you move from exception-based error handling to a more functional approach by making failure explicit. Instead of throwing exceptions, you can represent the absence of a value with nullable types (?) or model failures with Result and sealed classes.