DEV Community

Vin Lookup
Vin Lookup

Posted on

Handling Missing PlantCode and PlantCity from vPIC Without Fake Factory Labels

NHTSA vPIC often returns plant-related fields: PlantCode, PlantCity, PlantState, and PlantCountry. When they are populated, they help users understand where a VIN pattern is associated with assembly. When they are empty, blank, or "Not Applicable," product teams feel the gap. The temptation is to invent a factory name from the eleventh VIN character, a blog post table, or a hard-coded map that looked complete last year.

This post is about refusing that invention. Show plant data when vPIC provides it. When it does not, say so -- do not mint a fake plant label.

What plant fields are (and are not)

Plant fields in DecodeVinValues-style responses are catalog associations for the decoded VIN pattern. They are useful geography and plant identifiers when present. They are not a guarantee of the calendar day the vehicle was built, and they are not a license to fill nulls from tribal knowledge.

Position 11 of a VIN is often called the plant code in industry conversation. That character is part of the VIS structure. Mapping it to a human plant name without an authoritative, maintained source is how UIs ship "Detroit Assembly" for vehicles that never saw Detroit.

The overclaim pattern

// Bad: invent a factory from position 11 when vPIC is empty
const FAKE_PLANTS: Record<string, string> = {
  A: "Plant A - Mystery City",
  Z: "Legacy Factory",
};

function plantLabel(vin: string, plantCity: string | null): string {
  if (plantCity) return plantCity;
  return FAKE_PLANTS[vin[10]!] ?? "Unknown Plant";
}
Enter fullscreen mode Exit fullscreen mode

Even "Unknown Plant" as a proper noun is misleading if you style it like a real facility. Worse is a static map that drifts as manufacturers reassign codes. Empty vPIC fields mean "not provided," not "look up our folklore table."

Model absence explicitly

export type PlantView =
  | { status: "provided"; code: string | null; city: string | null; state: string | null; country: string | null }
  | { status: "not_provided" };

const EMPTY = new Set(["", "null", "undefined", "not applicable", "n/a"]);

function clean(raw: string | null | undefined): string | null {
  if (raw == null) return null;
  const s = raw.replace(/\s+/g, " ").trim();
  if (!s || EMPTY.has(s.toLowerCase())) return null;
  return s;
}

export function viewPlant(fields: {
  PlantCode?: string | null;
  PlantCity?: string | null;
  PlantState?: string | null;
  PlantCountry?: string | null;
}): PlantView {
  const code = clean(fields.PlantCode ?? null);
  const city = clean(fields.PlantCity ?? null);
  const state = clean(fields.PlantState ?? null);
  const country = clean(fields.PlantCountry ?? null);
  if (!code && !city && !state && !country) return { status: "not_provided" };
  return { status: "provided", code, city, state, country };
}

export function plantLines(view: PlantView): string[] {
  if (view.status === "not_provided") {
    return ["Assembly plant: not provided by NHTSA for this VIN"];
  }
  const lines: string[] = [];
  if (view.code) lines.push(`Plant code: ${view.code}`);
  const place = [view.city, view.state, view.country].filter(Boolean).join(", ");
  if (place) lines.push(`Plant location: ${place}`);
  if (lines.length === 0) {
    return ["Assembly plant: not provided by NHTSA for this VIN"];
  }
  return lines;
}
Enter fullscreen mode Exit fullscreen mode

Partial presence is fine: code without city, or city without code. Show what you have. Do not pad missing pieces with guesses so the card looks "complete."

UI copy that stays honest

  • Heading: "Assembly plant (NHTSA)" not "Built at"
  • Empty state: "Not provided by NHTSA for this VIN" -- not a gray factory icon with a made-up name
  • Optional note: position 11 may be visible in the raw VIN display, but do not auto-expand it into a city
  • Tooltips: explain that plant fields come from the decode catalog and can be blank for some patterns

If your marketplace needs plant geography for fraud heuristics, keep that logic server-side and separate from the consumer-facing label. A risk score can use WMI plus plant character; the buyer-facing panel still must not fabricate a factory name.

Tests that lock the policy

import assert from "node:assert/strict";

assert.equal(
  viewPlant({ PlantCode: "", PlantCity: "Not Applicable" }).status,
  "not_provided",
);

assert.deepEqual(
  plantLines(viewPlant({ PlantCity: " Georgetown ", PlantState: "KY", PlantCountry: null })),
  ["Plant location: Georgetown, KY"],
);

assert.equal(
  plantLines(viewPlant({})).join(" "),
  "Assembly plant: not provided by NHTSA for this VIN",
);
Enter fullscreen mode Exit fullscreen mode

Add a regression test that fails if any helper returns a string from a hard-coded plant map when all vPIC plant fields were empty. Invented factories tend to arrive through "helpful" formatters and contentful CMS snippets.

When you do maintain a map

Some internal tools maintain a reviewed WMI/plant reference. If you must, keep it:

  1. Versioned and dated
  2. Never the default for empty vPIC fields in consumer UI
  3. Labeled as "internal reference" not "NHTSA plant"
  4. Disabled in the public decode panel unless a human curated override exists for that exact VIN pattern

Public trust dies when a free decoder shows a confident city that the official decode left blank.

Takeaway

Missing PlantCode or PlantCity from vPIC is data absence, not a puzzle to solve with VIN position folklore. Pass through cleaned plant fields when present, model not_provided when they are not, and keep factory names out of the UI unless NHTSA (or another clearly labeled source) supplied them. Honest empty states beat fake assembly plants every time.

I maintain VIN Lookup, a free VIN decode based on NHTSA data.

Top comments (0)