All Behavioral questions
Shane's story bank for behavioral interviews, organized by question. Updated whenever a story gets better. Last updated 2026-09-25.
How to use this
- Every answer is STAR: Situation, Task, Action, Result. Say "I", not "we", for what you did.
- Toyota maps each question to a Toyota Way value. The value is in brackets after each heading.
- Aim for 60 to 90 seconds, then stop talking.
- Keep a mix: about half wins, half things that went wrong. Toyota asks for exactly that split.
- Anything in [brackets] is not confirmed yet. Don't say a bracketed detail until it's real.
- Multi-part questions: say the parts back first ("So: A, B and C. Let me take those in order"), answer each, and end on the yes/no part.
1. Walk me through a project you're proud of
"Creative Studio is PMG's ad-creative production platform. You give it one HTML ad template and a client's product catalog, and it renders every ad image the client needs, then delivers them for platforms like Meta and Pinterest.
The backend is Django and Postgres, with Redis for render progress and Celery workers on SQS for anything asynchronous. The API never renders anything itself. It creates a tracker in Redis, queues the job, and returns right away. A coordinator task works out what needs rendering and hands batches to a separate ECS fleet running headless Chromium, which uploads images to S3 and calls back as each one finishes.
Most of my time went into the dispatch layer, because that's what was breaking at scale. One client's template came to about 823,000 creatives, and a single Celery task was trying to walk all of them inside a 40-minute limit. It got killed every run, so renders never finished, and the dashboards still looked healthy because the retries kept resetting SQS's receive count.
My teammates wrote the design. I did the diagnosis behind it and built the core: a coordinator that fans the work out into small idempotent batches behind a feature flag, the completion accounting and dead-letter handling, an Athena diff that finds which catalog rows actually changed, and a monitor for renders that get stuck.
Happy to go deeper on any of that."
Credit boundary: teammates designed it (the ADR), you diagnosed and built the core. Say it that way every time.
2. A problem where the root cause wasn't obvious (Drive Curiosity)
"Large renders at PMG never finished, but they never errored either. They just inched forward every time someone hit Restart Render. The obvious guess was capacity, but the screenshot workers already scaled on queue backlog and were keeping up. So I went to the task logs instead of the dashboards.
Two things came out. First, all the work sat in one Celery task that had to walk about 823,000 combinations inside a fixed time limit, so it was killed mid-run every time. You can't scale your way out of that; one task is one task. Second, the task's retries published a fresh SQS message each time, which reset the receive count, so nothing ever reached the dead-letter queue and every graph looked healthy.
The logs also showed how wasteful it was: by the end, each run walked all 823,000 combinations to find 13 that still needed rendering.
That diagnosis fed the design my teammates wrote, and I built the core of it. Renders at that scale now finish, and failures show up instead of hiding."
3. A time you went and saw for yourself (Observe Thoroughly)
"Headless Chromium kept crashing in our containers, and nothing in the application code explained it. Instead of reasoning from the code, I looked at the actual running container and found its shared memory, /dev/shm, was at the 64MB default. Chromium needs more than that. Sizing it properly fixed the crashes. The answer wasn't in the place everyone was looking."
4. A time a team you were on wasn't working effectively
Version A: the render pipeline (verified)
"At PMG, large renders weren't finishing, and for a while the team couldn't tell why. The dashboards were green, the dead-letter queue was empty, and users kept hitting Restart Render. The team wasn't ineffective because of the people. It was ineffective because everything it relied on to spot failures said things were fine.
I went to the task logs and found the retries were resetting the receive count, so failures never reached the dead-letter queue. So I made failures show up honestly. Batches now go back on the queue to retry instead of using Celery's retry, so SQS keeps an accurate count, and batches that really fail land in the dead-letter queue. I built a drainer that reads those, records the batch as failed, and closes out the render. And when a render in staging hung four creatives short of 765,727 with no alert, I added a stuck-render check that alerts in Datadog.
Now a render ends as done or failed, instead of hanging until it silently expires after 24 hours. What I took from it: when a team isn't working well, first check whether they can even see what's happening."
If asked about tension on the team: the team worked well together. The problem was the tools. Don't invent a conflict.
Version B: the Slack bot (human story, brackets to fill)
"At PMG, I worked on a small internal project with another engineer and someone from our media team. We were asked to build a Slack bot around channel naming conventions, [because channels were being created with inconsistent names, which made them hard to find].
At first we weren't working well as a team. The brief was loose, and instead of pinning down the scope, each of us went off trying different things. We'd all assumed the bot should create channels for people automatically, with the convention built in.
About halfway through, we stepped back and asked: is this actually what they want? [I suggested we show them what we had before building any more.] That's when we found out we'd misunderstood. They didn't want the bot creating channels. They wanted it to guide people: you type a slash command, a form pops up that walks you through naming the channel correctly, and you're still the one who creates it.
So we re-scoped around that. [My part was rebuilding the bot around the slash command and the pop-up form.] [We shipped the guided version, and people started using it.]
The lesson for me was to confirm what 'done' looks like before writing code. Now I write the scope down in a few sentences and check it with whoever asked for it. It also taught me to think from the user's side: they didn't want to lose control of creating their own channels, they just wanted help getting it right."
To fill in: (1) what you personally did at the halfway point, (2) how you found out they wanted a guide, (3) your part in the rebuild, (4) the real result, even if it never shipped.
5. Build consensus among groups with conflicting objectives (Work with Integrity)
"During the render incident at PMG, the team split into two reasonable positions. One side said Celery itself was the problem: its retry behavior had hidden the failure, so we should replace it with our platform's own SQS consumer. The other side said the real bug was one task doing unbounded work, which would break under any task runner.
What got us to agreement was separating the two. Fix the unbounded work now, behind a feature flag so the old path stayed live and the cutover could be reversed. Treat replacing Celery as its own follow-up, not a prerequisite. Both sides got what they cared about: the people worried about risk had a kill switch, and the people who wanted Celery gone kept it on the roadmap.
My part was building what made that compromise workable: the fan-out coordinator behind that flag. The lesson I took is that most technical disagreements are two people protecting different risks, and if you can protect both, the argument goes away."
Honesty: the "I" is only what you built, not brokering the agreement. If you actually argued one of those positions, say which. It's two camps in one team, not separate work groups; a real cross-team example would fit better.
6. A peer insists his solution is better than yours (Welcome Competition, without ego)
"First I'd make sure I actually understand his solution, well enough to explain it back to him. A lot of disagreements are two people protecting different risks, so I'd ask what he's optimizing for and tell him what I'm optimizing for.
Then I'd make it about evidence instead of opinions: prototype both, measure them, or find the case that separates them. I saw that work on my team at PMG with batch sizing on the render pipeline. Instead of arguing over the right number, the team made it a setting and let production metrics decide.
If we still disagree, I'd bring it to the tech lead or manager together, openly, with both options written down. And if it goes his way, I commit to it fully and help make it work. My ego isn't in which solution wins, it's in whether the system works. On the render pipeline fix, the design came from my teammates, and I was the one who implemented it."
7. A time you reported something that wasn't good news (Work with Integrity)
"A bad feed load at PMG dropped 42,600 records. The cause was newline truncation combined with a duplicate same-day feed load landing in one S3 partition. I restored 837,714 of 849,131 records, 98.7%, across a 139,608-product catalog.
I didn't round that to 'fully recovered.' I reported the 1.3% that wasn't, and filed three follow-up items, because the same kind of bug could happen again. The value is in saying the number that isn't 100."
Call it "a bad feed load", not a "data incident", so it doesn't blur with the PMG departure story.
8. A failure, or something you'd do differently (Get Better and Better)
"I shipped the new dispatch path behind a feature flag and ran it in staging at real scale. It got to 765,723 of 765,727 and stopped. Four short.
The four weren't the real problem. The real problem was that nothing alarmed. A render whose callbacks stop arriving just sits there until a 24-hour cache timeout silently clears it. No error, no alert, and the evidence expires.
So I built a scheduled check that flags every render stuck past a threshold, and a Datadog monitor alerts on it. It scans each client separately, so one Redis hiccup can't blind the whole check.
What I'd do differently: I fixed the original failure without instrumenting the new failure mode my fix created. Now I ask 'how would I find out this broke?' before I call anything done."
9. Eliminating waste (Create Room to Grow)
"Every render at PMG walked the entire product catalog to decide what to render, even when almost nothing had changed. At the tail of an incident, each run walked about 823,000 combinations to find 13 that needed work.
I built the change-detection piece for the feed side: an Athena query that takes today's catalog snapshot and subtracts yesterday's with an EXCEPT, a set difference across two date partitions that already existed. No new columns, no hashing. That gives the render only the catalog rows that actually changed. It's just-in-time applied to data: stop producing things nobody asked for."
10. A small improvement that mattered (Continue the Quest for Improvement)
"At PMG I replaced 5,000 individual API calls with one batched call. [What the calls were, and what it sped up.] It was a small change that never got a design doc, but it's the kind of improvement that adds up."
To fill in: what the calls were, so the follow-up "what was it for?" has an answer.
11. Serving an internal customer (Act for Others)
"At a shared-services team, your customers are other engineers. At PMG, our dead-letter queue had been undecodable for eight days, which meant nobody on the team could see what was failing. I made it decodable, and it now drains in about 60 seconds.
While I was in there, I found a missing IAM permission, sqs:SendMessage. I didn't have the access to fix it and it belonged to someone else, so I handed it to the owner instead of working around it."
Say "found", never "fixed", for the IAM gap.
12. Respecting your teammates' work (Show Respect for People)
"On a platform, respect for people looks like not breaking the teams downstream of you. When I changed how the render pipeline dispatched work, I wrote tests alongside every change, especially the failure paths, and put the whole thing behind a feature flag. The flag wasn't for me. It meant that if I was wrong, turning it off was a config change, and nobody else's work had to go down with mine."
13. Learning something new fast (Get Better and Better)
"At Arch Capital I interned for about six months on the claims side, on the backend, in Java and Spring Boot with MySQL and Elasticsearch. I came in needing to get productive in an existing Java codebase quickly, in a large regulated insurance company with a real review process. In those six months I shipped 73 pull requests across four production repositories. [One specific PR you're proud of, in two sentences.]"
To fill in: one real PR from Arch, in case they ask for specifics. Don't mention Kubernetes unless you can back it up.
14. Why Toyota? Why not a startup? (plus the downtime question)
Take it in order, end on the yes/no:
"Two reasons. First, the kind of work. The work I liked most at an insurance company and at an agency was the enterprise side: systems a lot of other people depend on, where correctness and review really matter. Enterprise Shared Services is exactly that: platforms that teams across TFS build on. At a startup I'd be building one product fast. Here I'd be building things other teams trust.
Second, how Toyota works. I want strong engineers around me, real code review, and a clear process. What happened at PMG taught me how much I value working inside a process instead of around it. I'm looking for a place to build a career, not a stopgap.
And to your question about a month or two without much work: yes, completely. I'd use it to go deeper on the platform, the codebase and the docs, and ask you where I can help, and keep it inside what you've asked for."
Don't say you've never considered startups. "I've looked at both, and here's why this fits me now" is honest.
15. Giving credit (Thank People)
"The render pipeline fix wasn't mine alone. The design came from two senior engineers on my team, and I implemented it. When I found the IAM permission gap, someone else with the access fixed it. I try to say those things out loud, because the easiest way to lose a team's trust is to take credit for their part."
16. Solving a problem with incomplete or conflicting information (Observe Thoroughly)
Version A: the render pipeline (verified)
"At PMG, large renders weren't finishing, and the information I had conflicted. Users were telling us renders never completed. But every dashboard said the system was healthy: queue traffic looked normal, and the dead-letter queue, where failed work normally ends up, was empty.
When two sources disagree, I go to the most direct evidence I can find. The dashboards were summaries. The task logs were what actually happened. So I read the logs for the renders that weren't finishing. They showed the work was running in one long task that kept getting killed at its time limit, and that every retry published a fresh message, which reset SQS's receive count. Nothing ever looked like a failure. The dashboards weren't wrong about what they measured; they were measuring the wrong thing.
To decide what to do, I separated what I knew from what I was guessing. I knew the task was being killed and that the retries hid it. So the fix had to do two things: break the work into small batches that finish inside the limit, and make failures show up honestly. That became the design my teammates wrote, and I built the core of it.
What I took from it: when information conflicts, don't pick the source you like. Find the one closest to what actually happened."
Version B: the Slack bot (use this if the render story is already taken in the same interview loop)
"On a small internal project at PMG, our brief for a Slack bot was vague, and the three of us each filled the gaps with our own assumptions. We all assumed the bot should create channels automatically. Halfway through, [I noticed we couldn't point to anything in the brief that actually said that]. The missing information was what the people asking for it wanted, and the only reliable source for that was them. So [I suggested we demo what we had and ask].
They wanted a guide, not automation: a slash command that opens a form and walks you through naming the channel, with the person still creating it. We decided to re-scope around that instead of defending what we'd built.
The lesson: when requirements are incomplete, the cheapest fix is asking the person who wrote them, before you build more."
Don't use the render story for more than two questions in one interview loop. Toyota asks for diverse examples.
Change log
- 2026-09-25: first version. Built from the Toyota prep doc, corrected against the actual Creative Studio code (no watermark claim, no 1,983-test claim, no "tracing hooks" claim, staging wedge told the right way round). Added the Slack bot story (brackets to fill) and the downtime answer.
- 2026-09-25: published. Added "incomplete or conflicting information".
Comments