If your SwiftUI preview is crashing with the error "argument must be a string interpolation" and you're using OSLog.Logger, you're hitting a known conflict between Xcode's preview compiler and OSLog's special string handling.
The error
You'll see something like this in the preview diagnostics:
Compiling failed: argument must be a string interpolation
logger.debug(__designTimeString("#24265_0", fallback: "Some log message"))
`- error: argument must be a string interpolationThe key clue is __designTimeString -- you didn't write that. Xcode injected it.
Why this happens
There are two systems fighting each other:
OSLog requires string interpolation. Unlike a normal function that accepts a String, Logger.debug, Logger.info, Logger.error, etc. require a special OSLogInterpolation type. The Swift compiler creates this type automatically when you use string interpolation \() directly inside the logger call. This is how OSLog enforces privacy and performance at compile time. Plain string literals work too, because the compiler implicitly wraps them.
Xcode previews replace string literals. When building for previews, Xcode's compiler injects a function called __designTimeString around every string literal. This is what enables live editing of strings in the preview canvas.
So your code:
logger.debug("User completed onboarding")Becomes this during the preview build:
logger.debug(__designTimeString("#12345_0", fallback: "User completed onboarding"))The __designTimeString function returns a regular String, not the OSLogInterpolation that Logger.debug expects. Type mismatch. Compilation fails. Preview crashes.
The fix
Wrap the string in an explicit interpolation:
// Before (crashes in preview):
logger.debug("User completed onboarding")
// After (works in preview):
logger.debug("\(String("User completed onboarding"))")By making the argument an interpolation expression \(...), the preview compiler no longer sees a bare string literal and does not inject __designTimeString. The compiler correctly creates the OSLogInterpolation, and the preview builds successfully.
Apply it everywhere
You need to fix every Logger call that uses a plain string literal in files that are part of your preview's compilation. A quick way to find them:
# Find logger calls with plain string literals
grep -rn 'logger\.\(debug\|info\|warning\|error\|notice\|fault\)("' Sources/If you have many log statements, you can also create a helper that takes a plain String and uses print or a conditional #if DEBUG fallback during previews, though the interpolation wrapper is the most targeted fix.
Why not just use print?
OSLog.Logger is significantly better than print for production apps:
- Structured log levels (debug, info, error, fault)
- Privacy controls for sensitive data
- Visible in Console.app with filtering
- Near-zero overhead when not actively observed
The preview issue is a tooling quirk, not a reason to abandon OSLog.